authentik.api.v3.schema.query

 1from typing import Any
 2
 3from django.utils.translation import gettext_lazy as _
 4from drf_spectacular.generators import SchemaGenerator
 5from drf_spectacular.plumbing import (
 6    ResolvedComponent,
 7    build_basic_type,
 8    build_parameter_type,
 9)
10from drf_spectacular.types import OpenApiTypes
11from structlog.stdlib import get_logger
12
13LOGGER = get_logger()
14
15
16QUERY_PARAMS = {
17    "ordering": ResolvedComponent(
18        name="QueryPaginationOrdering",
19        type=ResolvedComponent.PARAMETER,
20        object="QueryPaginationOrdering",
21        schema=build_parameter_type(
22            name="ordering",
23            schema=build_basic_type(OpenApiTypes.STR),
24            location="query",
25            description=_("Which field to use when ordering the results."),
26        ),
27    ),
28    "page": ResolvedComponent(
29        name="QueryPaginationPage",
30        type=ResolvedComponent.PARAMETER,
31        object="QueryPaginationPage",
32        schema=build_parameter_type(
33            name="page",
34            schema=build_basic_type(OpenApiTypes.INT),
35            location="query",
36            description=_("A page number within the paginated result set."),
37        ),
38    ),
39    "page_size": ResolvedComponent(
40        name="QueryPaginationPageSize",
41        type=ResolvedComponent.PARAMETER,
42        object="QueryPaginationPageSize",
43        schema=build_parameter_type(
44            name="page_size",
45            schema=build_basic_type(OpenApiTypes.INT),
46            location="query",
47            description=_("Number of results to return per page."),
48        ),
49    ),
50    "search": ResolvedComponent(
51        name="QuerySearch",
52        type=ResolvedComponent.PARAMETER,
53        object="QuerySearch",
54        schema=build_parameter_type(
55            name="search",
56            schema=build_basic_type(OpenApiTypes.STR),
57            location="query",
58            description=_("A search term."),
59        ),
60    ),
61    # Not related to pagination but a very common query param
62    "name": ResolvedComponent(
63        name="QueryName",
64        type=ResolvedComponent.PARAMETER,
65        object="QueryName",
66        schema=build_parameter_type(
67            name="name",
68            schema=build_basic_type(OpenApiTypes.STR),
69            location="query",
70        ),
71    ),
72}
73
74
75def postprocess_schema_query_params(
76    result: dict[str, Any], generator: SchemaGenerator, **kwargs
77) -> dict[str, Any]:
78    """Optimize pagination parameters, instead of redeclaring parameters for each endpoint
79    declare them globally and refer to them"""
80    LOGGER.debug("Deduplicating query parameters")
81    for path in result["paths"].values():
82        for method in path.values():
83            for idx, param in enumerate(method.get("parameters", [])):
84                if param["name"] not in QUERY_PARAMS:
85                    continue
86                method["parameters"][idx] = QUERY_PARAMS[param["name"]].ref
87    return result
LOGGER = <BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>
QUERY_PARAMS = {'ordering': <drf_spectacular.plumbing.ResolvedComponent object>, 'page': <drf_spectacular.plumbing.ResolvedComponent object>, 'page_size': <drf_spectacular.plumbing.ResolvedComponent object>, 'search': <drf_spectacular.plumbing.ResolvedComponent object>, 'name': <drf_spectacular.plumbing.ResolvedComponent object>}
def postprocess_schema_query_params( result: dict[str, typing.Any], generator: drf_spectacular.generators.SchemaGenerator, **kwargs) -> dict[str, typing.Any]:
76def postprocess_schema_query_params(
77    result: dict[str, Any], generator: SchemaGenerator, **kwargs
78) -> dict[str, Any]:
79    """Optimize pagination parameters, instead of redeclaring parameters for each endpoint
80    declare them globally and refer to them"""
81    LOGGER.debug("Deduplicating query parameters")
82    for path in result["paths"].values():
83        for method in path.values():
84            for idx, param in enumerate(method.get("parameters", [])):
85                if param["name"] not in QUERY_PARAMS:
86                    continue
87                method["parameters"][idx] = QUERY_PARAMS[param["name"]].ref
88    return result

Optimize pagination parameters, instead of redeclaring parameters for each endpoint declare them globally and refer to them