Skip to content

Commit

Permalink
Parent URL resolver match parameters support (#373)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalik committed Sep 5, 2023
1 parent 5d4ceea commit 3b64989
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 21 deletions.
14 changes: 9 additions & 5 deletions ninja/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,10 +406,9 @@ def _get_urls(self) -> List[Union[URLResolver, URLPattern]]:
result.append(get_root_url(self))
return result

@property
def root_path(self) -> str:
def get_root_path(self, path_params: DictStrAny) -> str:
name = f"{self.urls_namespace}:api-root"
return reverse(name)
return reverse(name, kwargs=path_params)

def create_response(
self,
Expand Down Expand Up @@ -441,9 +440,14 @@ def create_temporal_response(self, request: HttpRequest) -> HttpResponse:
def get_content_type(self) -> str:
return "{}; charset={}".format(self.renderer.media_type, self.renderer.charset)

def get_openapi_schema(self, path_prefix: Optional[str] = None) -> OpenAPISchema:
def get_openapi_schema(
self,
*,
path_prefix: Optional[str] = None,
path_params: Optional[DictStrAny] = None,
) -> OpenAPISchema:
if path_prefix is None:
path_prefix = self.root_path
path_prefix = self.get_root_path(path_params or {})
return get_schema(api=self, path_prefix=path_prefix)

def get_openapi_operation_id(self, operation: "Operation") -> str:
Expand Down
22 changes: 14 additions & 8 deletions ninja/openapi/docs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json
import os
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Any, Optional

from django.conf import settings
from django.http import HttpRequest, HttpResponse
Expand All @@ -20,11 +20,13 @@

class DocsBase(ABC):
@abstractmethod
def render_page(self, request: HttpRequest, api: "NinjaAPI") -> HttpResponse:
def render_page(
self, request: HttpRequest, api: "NinjaAPI", **kwargs: Any
) -> HttpResponse:
pass # pragma: no cover

def get_openapi_url(self, api: "NinjaAPI") -> str:
return reverse(f"{api.urls_namespace}:openapi-json")
def get_openapi_url(self, api: "NinjaAPI", path_params: DictStrAny) -> str:
return reverse(f"{api.urls_namespace}:openapi-json", kwargs=path_params)


class Swagger(DocsBase):
Expand All @@ -41,8 +43,10 @@ def __init__(self, settings: Optional[DictStrAny] = None):
if settings:
self.settings.update(settings)

def render_page(self, request: HttpRequest, api: "NinjaAPI") -> HttpResponse:
self.settings["url"] = self.get_openapi_url(api)
def render_page(
self, request: HttpRequest, api: "NinjaAPI", **kwargs: Any
) -> HttpResponse:
self.settings["url"] = self.get_openapi_url(api, kwargs)
context = {
"swagger_settings": json.dumps(self.settings, indent=1),
"api": api,
Expand All @@ -62,10 +66,12 @@ def __init__(self, settings: Optional[DictStrAny] = None):
if settings:
self.settings.update(settings)

def render_page(self, request: HttpRequest, api: "NinjaAPI") -> HttpResponse:
def render_page(
self, request: HttpRequest, api: "NinjaAPI", **kwargs: Any
) -> HttpResponse:
context = {
"redoc_settings": json.dumps(self.settings, indent=1),
"openapi_json_url": self.get_openapi_url(api),
"openapi_json_url": self.get_openapi_url(api, kwargs),
"api": api,
}
return render_template(request, self.template, self.template_cdn, context)
Expand Down
12 changes: 6 additions & 6 deletions ninja/openapi/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, NoReturn
from typing import TYPE_CHECKING, Any, NoReturn

from django.http import Http404, HttpRequest, HttpResponse

Expand All @@ -10,17 +10,17 @@
from ninja import NinjaAPI # pragma: no cover


def default_home(request: HttpRequest, api: "NinjaAPI") -> NoReturn:
def default_home(request: HttpRequest, api: "NinjaAPI", **kwargs: Any) -> NoReturn:
"This view is mainly needed to determine the full path for API operations"
docs_url = f"{request.path}{api.docs_url}".replace("//", "/")
raise Http404(f"docs_url = {docs_url}")


def openapi_json(request: HttpRequest, api: "NinjaAPI") -> HttpResponse:
schema = api.get_openapi_schema()
def openapi_json(request: HttpRequest, api: "NinjaAPI", **kwargs: Any) -> HttpResponse:
schema = api.get_openapi_schema(path_params=kwargs)
return Response(schema)


def openapi_view(request: HttpRequest, api: "NinjaAPI") -> HttpResponse:
def openapi_view(request: HttpRequest, api: "NinjaAPI", **kwargs: Any) -> HttpResponse:
docs: DocsBase = api.docs
return docs.render_page(request, api)
return docs.render_page(request, api, **kwargs)
2 changes: 1 addition & 1 deletion tests/test_docs/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_examples():

response = client.get("/events/2020/1/1")
assert response.json() == {"date": "2020-01-01"}
schema = api.get_openapi_schema("")
schema = api.get_openapi_schema(path_prefix="")
events_params = schema["paths"]["/events/{year}/{month}/{day}"]["get"][
"parameters"
]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_docs/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def test_examples():
}
}

schema = api.get_openapi_schema("")
schema = api.get_openapi_schema(path_prefix="")
params = schema["paths"]["/filter"]["get"]["parameters"]
# print(params)
assert params == [
Expand Down

0 comments on commit 3b64989

Please sign in to comment.