Public API#
Controller#
- class dmr.controller.Controller(**kwargs)[source]#
Bases:
View,Generic[_SerializerT_co]Defines API views as controllers.
Controller is a
django.views.generic.base.Viewsubclass that should be used as a base for all REST endpoints.- endpoint_cls#
Class to create endpoints with.
- Type:
ClassVar[type[dmr.endpoint.Endpoint]]
- serializer#
Serializer that is passed via type parameters. The main goal of the serializer is to serialize object to json and deserialize them from json. You can’t change the serializer simply by modifying the attribute in the controller class. Because it is already passed to many other places. To customize it: create a new class, subclass
BaseSerializer, and pass the new type as a type argument to the controller.- Type:
ClassVar[type[dmr.serializer.BaseSerializer]]
- settings_validator_cls#
Runs settings validation once the first controller is created.
- Type:
ClassVar[type[dmr.validation.settings.SettingsValidator]]
- no_validate_http_spec#
Set of http spec validation checks that we disable for this class. Overrides the settings value, can be overridden per endpoint. Set it to
Noneto enable all checks back.- Type:
ClassVar[collections.abc.Set[dmr.settings.HttpSpec] | typing_extensions.sentinel | None]
- validate_responses#
Boolean whether or not validating responses. Works in runtime, can be disabled for better performance.
- Type:
ClassVar[bool | typing_extensions.sentinel]
- exclude_validate_responses#
Set of status codes that we don’t validate, even when
validate_responsesis enabled. Useful for errors like500that can be raised from anywhere and that you might not want to describe. Overrides the settings value, can be overridden per endpoint. Set it toNoneto validate all status codes back.- Type:
ClassVar[collections.abc.Set[http.HTTPStatus] | typing_extensions.sentinel | None]
- semantic_schema#
Should we generate any semantic schema for endpoints in this controller?
- Type:
ClassVar[bool | typing_extensions.sentinel]
- semantic_responses#
Should semantic responses be collected from different providers for all endpoints in this class.
- Type:
ClassVar[bool | typing_extensions.sentinel]
- exclude_semantic_responses#
Set of semantic responses that user wants to disable. Overrides the settings value, can be overridden per endpoint. Set it to
Noneto enable all semantic responses back.- Type:
ClassVar[collections.abc.Set[http.HTTPStatus] | typing_extensions.sentinel | None]
- semantic_auth#
Should semantic auth be collected from different providers for this endpoint. Overrides settings value.
- Type:
- exclude_semantic_auth#
Set of semantic security requirements names that should not be collected. Overrides settings value.
- Type:
collections.abc.Set[str] | typing_extensions.sentinel | None
- responses#
List of responses schemas that this controller can return. Overrides
'responses'key in the settings, can be overridden per endpoint. Set it toNoneto not use any responses from the settings.- Type:
ClassVar[collections.abc.Sequence[dmr.metadata.ResponseSpec] | typing_extensions.sentinel | None]
- allowed_http_methods#
Set of names to be treated as names for endpoints. Does not include
options, but includesmeta.- Type:
ClassVar[collections.abc.Set[str]]
- parsers#
Sequence of parsers to be used for this controller to parse incoming request’s body. All instances must be of subtypes of
Parser. Overrides the settings value, can be overridden per endpoint.- Type:
ClassVar[collections.abc.Sequence[dmr.parsers.Parser] | typing_extensions.sentinel]
- renderers#
Sequence of renderers to be used for this controller to render response’s body. All instances must be of subtypes of
Renderer. Overrides the settings value, can be overridden per endpoint.- Type:
ClassVar[collections.abc.Sequence[dmr.renderers.Renderer] | typing_extensions.sentinel]
- validate_negotiation#
Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?- Type:
ClassVar[bool | typing_extensions.sentinel]
- auth#
Sequence of auth instances to be used for this controller. Sync controllers must use instances of
dmr.security.SyncAuth. Async controllers must use instances ofdmr.security.AsyncAuth. Overrides the settings value, can be overridden per endpoint. Set it toNoneto disable auth of this controller.- Type:
ClassVar[collections.abc.Sequence[dmr.security.base.SyncAuth] | collections.abc.Sequence[dmr.security.base.AsyncAuth] | typing_extensions.sentinel | None]
- throttling#
Sequence of throttle instances to be used. Sync controllers must use instances of
dmr.throttling.SyncThrottle. Async controllers must use instances ofdmr.throttling.AsyncThrottle. Overrides the settings value, can be overridden per endpoint. Set it toNoneto disable throttling of this controller.
- error_model#
Schema type that represents and validates common error responses.
- Type:
ClassVar[Any]
- is_abstract#
Whether or not this controller is abstract. We consider controller “abstract” when it does not have exact serializer type or exact
api_endpointsinstances. You can also set it toTrueexplicitly to make a controller with an exact serializer reusable without routing it: it does not build any endpoints, only its subclasses do. Subclasses that don’t declareis_abstractthemselves become concrete again. Abstract controllers cannot be routed,as_viewraisesEndpointMetadataErrorfor them.- Type:
ClassVar[bool]
- extras#
Default extras instance for this controller. Setting it enables
extras=in@modifyand@validatefor all endpoints and provides controller-level defaults.EMPTYmeans that extras are not supported. See Providing extras for @modify and @validate to learn more.- Type:
ClassVar[dmr.internal.endpoint.Extras[Any] | typing_extensions.sentinel]
- controller_validator_cls#
Runs full controller validation on definition.
- Type:
ClassVar[type[dmr.validation.controller.ControllerValidator]]
- annotations_context#
Inference context to call
typing.get_type_hints()for this controller.- Type:
ClassVar[dmr.types.AnnotationsContext]
- api_endpoints#
Dictionary of HTTPMethod name to controller instance.
- Type:
ClassVar[collections.abc.Mapping[str, dmr.endpoint.Endpoint]]
- csrf_exempt#
Should this controller be exempted from the CSRF check? Is
Trueby default. See CSRF to configure the CSRF correctly to support REST responses. It is only supported on the controller level, because it has its own per-method logic inside Django’s original CSRF middleware.- Type:
ClassVar[bool]
- login_required#
Whether this controller should be handled by Django’s
LoginRequiredMiddleware. IsFalseby default. Users should make use of authentication indjango-modern-rest. See How authentication works for more details.- Type:
ClassVar[bool]
- summary#
A short summary of what this path item does. Defaults to the first paragraph of the controller’s docstring. Set it to
Noneto have no summary at all.- Type:
ClassVar[str | django.utils.functional.Promise | typing_extensions.sentinel | None]
- description#
A verbose explanation of the path item behavior. Defaults to everything that goes after the first paragraph of the controller’s docstring. Set it to
Noneto have no description at all.- Type:
ClassVar[str | django.utils.functional.Promise | typing_extensions.sentinel | None]
- tags#
A list of tags to group all operations from this controller in OpenAPI documentation. Overrides router-level tags, can be overridden per endpoint. Set it to
Noneto have no tags at all.- Type:
ClassVar[collections.abc.Sequence[str] | typing_extensions.sentinel | None]
- security#
A sequence of security requirement objects for all operations in this controller. Overrides
securityofdmr.openapi.OpenAPIConfig, can be overridden per endpoint. Set it toNoneto disablesecurityfor this controller. It is merged with the requirements generated fromauth, but it never affects the runtime auth. Useful to document external security mechanisms, for example, the ones enforced by an HTTP proxy. Used security schemes must be declared assecurity_schemesincomponentsofdmr.openapi.OpenAPIConfig. See Customizing security.- Type:
ClassVar[collections.abc.Sequence[dict[str, list[str]]] | typing_extensions.sentinel | None]
- servers#
An alternative servers array to service all operations in this controller. Can be overridden per endpoint. Set it to
Noneto have no servers at all.- Type:
ClassVar[collections.abc.Sequence[dmr.openapi.objects.server.Server] | typing_extensions.sentinel | None]
- deprecated#
Declares all operations in this controller to be deprecated. Overrides router-level value, can be overridden per endpoint.
- Type:
ClassVar[bool | typing_extensions.sentinel]
- external_docs#
Additional external documentation for all operations in this controller. Can be overridden per endpoint. Set it to
Noneto have no external docs at all.- Type:
ClassVar[dmr.openapi.objects.external_documentation.ExternalDocumentation | typing_extensions.sentinel | None]
- callbacks#
A map of possible out-of band callbacks related to all operations in this controller. Can be overridden per endpoint. Set it to
Noneto have no callbacks at all.
- x_extensions#
Specification extensions of the
PathItemof this controller, keys must start withx-. Unlike other OpenAPI attributes, it is not a default for the operations: every OpenAPI object has its own extensions, so nothing is inherited or merged. Usex_extensionsofmodify()orvalidate()for an operation.- Type:
ClassVar[collections.abc.Mapping[str, Any] | None]
- ignore_from_spec#
If set to
True, all endpoints from this controller would not be added to the final OpenAPI spec.- Type:
ClassVar[bool]
- request#
Current
HttpRequestinstance.
- args#
Path positional parameters of the request.
Changed in version 0.16.0: Explicit
is_abstractdefinitions are now respected: abstract controllers do not build any endpoints. Addeddeprecated,external_docs,callbacks, andx_extensions.serversis now resolved per endpoint and dumped on operations, not on the path item.- classmethod as_view(**initkwargs: Any) Callable[[...], HttpResponseBase][source]#
Returns a view function for the class-based view.
This override applies CSRF exemption to the view. Session-based authentication will still be explicitly validated for CSRF, while all other authentication methods will be CSRF-exempt.
This override also applies whether a login is required or not. By default, login is not required to exempt the view from Django’s
LoginRequiredMiddleware. Users should make use of authentication indjango-modern-rest. See How authentication works for more details.- Raises:
EndpointMetadataError – When called on an abstract controller, because it has nothing to serve.
Changed in version 0.16.0: Abstract controllers now raise
EndpointMetadataErrorinstead of silently returning a broken view.Controllers now set
login_requiredtoFalseby default in order to exempt controllers from Django’sLoginRequiredMiddleware.
- dispatch(request: HttpRequest, *args: Any, **kwargs: Any) HttpResponseBase[source]#
Find an endpoint that serves this HTTP method and call it.
Return 405 if this method is not allowed.
- format_error(error: str | Exception, *, loc: str | list[str | int] | None = None, error_type: str | ErrorType | None = None) Any[source]#
Convert error to the common format.
- Parameters:
error – A serialization exception like a validation error.
loc – Location where this error happened. Like
"headers", or"field_name", or["parsed_headers", "header_name"].error_type – Optional type of the error for extra metadata.
- Returns:
Simple python object - exception converted to a common format.
- classmethod get_schema(route_metadata: InternalRouteMetadata, context: OpenAPIContext, router: Router) PathItem | None[source]#
Generate OpenAPI spec for path items.
Changed in version 0.13.0:
Renamed from
get_path_itemtoget_schemaNow allows to return
Noneto ignore whole path items from OpenAPI schema
Changed in version 0.16.0:
summaryanddescriptionare now parsed from the controller’s docstring when they are not set explicitly. Changed path and pattern parameters to be route_metadata instead.serversis not set on the path item anymore, it is resolved per endpoint instead.
- async handle_async_error(endpoint: Endpoint, controller: Controller[_SerializerT_co], exc: Exception) HttpResponse[source]#
Return error response if possible. Async case.
Override this method to add custom error handling for async execution. By default - does nothing, only re-raises the passed error. Won’t be called when using sync endpoints.
- handle_error(endpoint: Endpoint, controller: Controller[_SerializerT_co], exc: Exception) HttpResponse[source]#
Return error response if possible. Sync case.
Override this method to add custom error handling for sync execution. By default - does nothing, only re-raises the passed error. Won’t be called when using async endpoints.
- handle_method_not_allowed(method: str) HttpResponse[source]#
Return error response for 405 response code.
It is special in way that we don’t have an endpoint associated with it.
- http_method_not_allowed(request: HttpRequest, *args: Any, **kwargs: Any) HttpResponse[source]#
Do not use, use
handle_method_not_allowed()instead.View.http_method_not_allowedraises an error in a wrong format.
- options(request: HttpRequest, *args: Any, **kwargs: Any) HttpResponse[source]#
Do not use, define your own meta method instead.
Django’s View.options has incompatible signature with
django-modern-rest. It would be a typing error to define something like:Warning
Don’t do this!
>>> from http import HTTPStatus >>> from dmr import Controller, validate >>> from dmr.plugins.pydantic import ( ... PydanticSerializer, ... ) >>> class MyController(Controller[PydanticSerializer]): ... @validate( ... ResponseSpec( ... None, ... status_code=HTTPStatus.NO_CONTENT, ... ), ... ) ... def options(self) -> HttpResponse: # <- typing problem ... ...
That’s why instead of
optionsyou should define our ownmetamethod:>>> class MyController(Controller[PydanticSerializer]): ... @validate( ... ResponseSpec( ... None, ... status_code=HTTPStatus.NO_CONTENT, ... ), ... ) ... def meta(self) -> HttpResponse: ... allow = ','.join( ... method.upper() ... for method in self.allowed_http_methods ... ) ... return self.to_response( ... None, ... status_code=HTTPStatus.NO_CONTENT, ... headers={'Allow': allow}, ... )
Note
By default
metamethod is not provided for you. If you want to supportOPTIONShttp method with the default implementation, use:>>> from dmr.options_mixins import MetaMixin >>> class ControllerWithMeta( ... MetaMixin, ... Controller[PydanticSerializer], ... ): ...
- setup(request: HttpRequest, *args: Any, **kwargs: Any) None[source]#
Set request context.
Unlike
setup()does not setheadmethod automatically.Thread safety: there’s only one controller instance per request.
- to_error(raw_data: Any, *, status_code: HTTPStatus, headers: Mapping[str, str] | None = None, cookies: Mapping[str, NewCookie] | None = None, renderer: Renderer | None = None) HttpResponse[source]#
Helpful method to convert API error parts into an actual error.
Always requires the error code to be passed. Is an alias for
to_responsemethod with a siglightly different signature and semantics.Should be always used instead of using raw
django.http.HttpResponseobjects. Does the usual validation, no “second validation” problem exists.
- to_response(raw_data: Any, *, status_code: HTTPStatus | None = None, headers: Mapping[str, str] | None = None, cookies: Mapping[str, NewCookie] | None = None, renderer: Renderer | None = None) HttpResponse[source]#
Helpful method to convert response parts into an actual response.
Should be always used instead of using raw
django.http.HttpResponseobjects. Has better serialization speed and semantics than manual. Does the usual validation, no “second validation” problem exists.
Endpoint#
- class dmr.endpoint.Endpoint(func: Callable[[...], Any], *, controller_cls: type[Controller[BaseSerializer]])[source]#
Represents the single API endpoint.
Is built during the import time. In the runtime only does response validate, which can be disabled.
Changed in version 0.16.0: Endpoint no longer creates
HttpResponseBaseobjects from modifications, nowResponseValidatorreturns full responses.funcis now public, but__call__is removed.- get_schema(route_metadata: InternalRouteMetadata, controller_cls: type[Controller[BaseSerializer]], context: OpenAPIContext, router: Router) Operation[source]#
Build an OpenAPI Operation from an endpoint.
Changed in version 0.16.0: Now accepts controller_cls parameter instead of controller_name and serializer. Changed path and pattern parameters to be route_metadata.
- async handle_async_error(controller: Controller[BaseSerializer], exc: Exception) HttpResponse[source]#
Return error response if possible.
Override this method to change the endpoint error handling logic.
Changed in version 0.16.0: Now you can raise different errors from layers above. Which would be handled by lower layers.
- handle_error(controller: Controller[BaseSerializer], exc: Exception) HttpResponseBase[source]#
Return error response if possible.
Override this method to change the endpoint error handling logic.
Changed in version 0.16.0: Now you can raise different errors from layers above. Which would be handled by lower layers.
- metadata_builder_cls#
alias of
EndpointMetadataBuilder
- metadata_cls#
alias of
EndpointMetadata
- metadata_merger_cls#
alias of
MetadataMerger
- metadata_validator_cls#
alias of
EndpointMetadataValidator
- payload_builder_cls#
alias of
PayloadBuilder
- request_negotiator_cls#
alias of
RequestNegotiator
- response_modification_cls#
alias of
ResponseModification
- response_negotiator_cls#
alias of
ResponseNegotiator
- response_validator_cls#
alias of
ResponseValidator
- serializer_context_cls#
alias of
SerializerContext
- class dmr.metadata.EndpointMetadata(*, endpoint_name: str, type_annotations: dict[str, Any], responses: dict[HTTPStatus, ResponseSpec], validate_responses: bool, method: str, modification: ResponseModification | None, error_handler: SyncErrorHandler | AsyncErrorHandler | None, component_parsers: list[ComponentParserSpec], parsers: dict[str, Parser], renderers: dict[str, Renderer], validate_negotiation: bool, auth: list[_AuthT] | None, throttling_before_auth: list[_ThrottlingT] | None, throttling_after_auth: list[_ThrottlingT] | None, exclude_validate_responses: frozenset[HTTPStatus], no_validate_http_spec: frozenset[HttpSpec], allowed_http_methods: frozenset[str], semantic_schema: bool, semantic_responses: bool, exclude_semantic_responses: frozenset[HTTPStatus], semantic_auth: bool, exclude_semantic_auth: frozenset[str], summary: str | Promise | None, description: str | Promise | None, tags: list[str] | sentinel | None, operation_id: str | None, deprecated: bool | sentinel, security: list[SecurityRequirement] | None, external_docs: ExternalDocumentation | None, callbacks: dict[str, Callback | Reference] | None, servers: list[Server] | None, x_extensions: dict[str, Any] | None, ignore_from_spec: bool, extras: _ExtrasT)[source]#
Base class for common endpoint metadata.
- type_annotations#
Unmodified unnotations of the endpoint function, returned by the resolution method.
- responses#
Mapping of HTTP method to response description. All possible responses that this API can return. Used for OpenAPI spec generation and for response validation.
- validate_responses#
Do we have to run runtime validation of responses for this endpoint? Already resolved from the global setting, the controller, and the endpoint.
- Type:
- modification#
Default modifications that are applied to the returned data. Can be
None, when@validateis used.- Type:
- error_handler#
Callback function to be called when this endpoint faces an exception.
- Type:
SyncErrorHandler | AsyncErrorHandler | None
- component_parsers#
List of component parser specifications from the controller. Each spec is a named tuple of (ComponentParser instance, model, model meta, default).
- Type:
- parsers#
List of instances to be used for this endpoint to parse incoming request’s body. All instances must be of subtypes of
Parser.
- renderers#
List of instances to be used for this endpoint to render response’s body. All instances must be of subtypes of
Renderer.
- validate_negotiation#
Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?- Type:
- auth#
list of auth instances to be used for this endpoint. Sync endpoints must use instances of
dmr.security.SyncAuth. Async endpoints must use instances ofdmr.security.AsyncAuth. When set it toNoneit means that auth is disabled for this endpoint.- Type:
list[dmr.metadata._AuthT] | None
- throttling#
Sequence of throttle instances to be used for this endpoint. Sync endpoints must use instances of
dmr.throttling.SyncThrottle. Async endpoints must use instances ofdmr.throttling.AsyncThrottle. Set it toNoneto disable throttling of this endpoint.- Type:
list[dmr.metadata._ThrottlingT] | None
- throttling_before_auth#
Sequence of throttle instances to be used before auth checks.
- Type:
list[dmr.metadata._ThrottlingT] | None
- throttling_after_auth#
Sequence of throttle instances to be used after auth checks.
- Type:
list[dmr.metadata._ThrottlingT] | None
- exclude_validate_responses#
Set of status codes that we don’t validate, even when
validate_responsesis enabled.- Type:
- no_validate_http_spec#
Set of checks that user wants to disable for validation in this endpoint.
- allowed_http_methods#
Set of extra HTTP methods that are allowed for this endpoint.
- exclude_semantic_responses#
Set of semantic responses that user wants to disable.
- Type:
- summary#
A short summary of what the operation does.
- Type:
str | django.utils.functional.Promise | None
- description#
A verbose explanation of the operation behavior.
- Type:
str | django.utils.functional.Promise | None
- tags#
A list of tags for API documentation control. Used to group operations in OpenAPI documentation. Already resolved from the endpoint and the controller,
EMPTYmeans that router-level tags are used during the schema generation.- Type:
list[str] | typing_extensions.sentinel | None
- deprecated#
Declares this operation to be deprecated. Already resolved from the endpoint and the controller,
EMPTYmeans that the router-level value is used during the schema generation.- Type:
- security#
A declaration of which security mechanisms can be used for this operation. List of security requirement objects. Already resolved from the endpoint, the controller, and
securityofOpenAPIConfigfrom the settings: the first explicitly defined level wins. They are merged with the requirements fromauthduring the schema generation. When set toNoneit means that no user provided security is used for this endpoint.- Type:
list[SecurityRequirement] | None
- external_docs#
Additional external documentation for this operation. Already resolved from the endpoint and the controller.
- Type:
ExternalDocumentation | None
- callbacks#
A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. Already resolved from the endpoint and the controller.
- servers#
An alternative servers array to service this operation. If a servers array is specified at the OpenAPI Object level, it will be overridden by this value. Already resolved from the endpoint and the controller.
- x_extensions#
Specification extensions of this operation, keys must start with
x-. Endpoint-only field, it is never resolved from the controller:Controller.x_extensionsdescribes the path item.
- ignore_from_spec#
If set to
True, this endpoint would not be added to the final OpenAPI spec.- Type:
- extras#
Extra settings for custom controllers, built by
build()ofextras. It isNonewhen the controller does not support extras. See Providing extras for @modify and @validate to learn more.- Type:
dmr.metadata._ExtrasT
methodcan be a custom name, not specified inhttp.HTTPMethodenum, whenallowed_http_methodsis used for endpoint definition. This might be useful for cases like when you need to define a method likequery, which is not yet formally accepted. Or provide domain specific HTTP methods.Changed in version 0.16.0: It is now a generic class. extras is added.
- collect_response_specs(controller_cls: type[Controller[BaseSerializer]], existing_responses: dict[HTTPStatus, ResponseSpec]) list[ResponseSpec][source]#
Collect unique responses for all possible response providers.
- response_spec_providers() list[ResponseSpecProvider][source]#
Determine: from where we should collect response schemas.
Override this method in your own metadata classes if you want more or less response spec providers.
For example: you can add some custom field to
Controllerlikechecks=. And you can subclassEndpointMetadatato also containchecksfield and override this method to also include response specs from this field.Define
semantic_responsestoFalseon settings or controller level to disable semantic responses collection.
- dmr.endpoint.request_endpoint(request: HttpRequest, *, strict: Literal[True]) Endpoint[source]#
- dmr.endpoint.request_endpoint(request: HttpRequest, *, strict: bool = False) Endpoint | None
Return an instance of the
Endpointthat was used for this request.When strict is passed and request has no endpoint, we raise
AttributeError. This can happen for405responses, for example. They don’t have endpoints. All others do.Added in version 0.7.0.
Modify#
- final class dmr.endpoint.ModifyEndpoint(extras_cls: type[_ExtrasT] | sentinel = EMPTY)[source]#
Decorator to modify endpoints that return raw model data.
Apply it to change some API parts:
>>> from http import HTTPStatus >>> from dmr import Controller, modify >>> from dmr.plugins.pydantic import PydanticFastSerializer >>> class TaskController(Controller[PydanticFastSerializer]): ... @modify(status_code=HTTPStatus.ACCEPTED) ... def post(self) -> list[int]: ... return [1, 2] # id of tasks you have started
- Parameters:
status_code – Shows status_code in the documentation. When status_code is passed, always use it by default. When not provided, we use smart inference based on the HTTP method name for default returned response.
headers – Shows headers in the documentation. When headers are passed we will add them for the default response.
cookies – Shows cookies in the documentation. When cookies are passed we will add them for the default response.
validate_responses – Do we have to run runtime validation of responses for this endpoint? Customizable via global setting, per controller, and per endpoint. Here we only store the per endpoint information.
exclude_validate_responses – Set of status codes that we don’t validate, even when
validate_responsesis enabled. Useful for errors like500that can be raised from anywhere and that you might not want to describe. Overrides controller and settings values. Set it toNoneto validate all status codes back.semantic_schema – Should we generate any semantic schema for this endpoint?
semantic_responses – Should semantic responses be collected from different providers for this endpoint.
exclude_semantic_responses – Set of semantic responses status codes that user wants to disable. Overrides controller and settings values. Set it to
Noneto enable all semantic responses back.semantic_auth – Should semantic auth be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_auth – Set of semantic security requirements names that should not be collected. Overrides controller and settings values.
extra_responses – Sequence of extra responses that this endpoint can return. Overrides controller and settings values. Set it to
Noneto only use the default response.no_validate_http_spec – Set of http spec validation checks that we disable for this endpoint. Overrides controller and settings values. Set it to
Noneto enable all checks back.error_handler – Callback function to be called when this endpoint faces an exception.
parsers – Sequence of types to be used for this endpoint to parse incoming request’s body. All types must be subtypes of
Parser. Overrides controller and settings values.renderers – Sequence of types to be used for this endpoint to render response’s body. All types must be subtypes of
Renderer. Overrides controller and settings values.validate_negotiation – Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?auth – Sequence of auth instances to be used for this endpoint. Sync endpoints must use instances of
dmr.security.SyncAuth. Async endpoints must use instances ofdmr.security.AsyncAuth. Overrides controller and settings values. Set it toNoneto disable auth for this endpoint.throttling – Sequence of throttle instances to be used for this endpoint. Sync endpoints must use instances of
dmr.throttling.SyncThrottle. Async endpoints must use instances ofdmr.throttling.AsyncThrottle. Overrides controller and settings values. Set it toNoneto disable throttling of this endpoint.summary – A short summary of what the operation does. Defaults to the first paragraph of the endpoint’s docstring. Set it to
Noneto have no summary at all.description – A verbose explanation of the operation behavior. Defaults to everything that goes after the first paragraph of the endpoint’s docstring. Set it to
Noneto have no description at all.tags – A sequence of tags for API documentation control. Used to group operations in OpenAPI documentation. Overrides controller-level and router-level tags. Set it to
Noneto have no tags at all.operation_id – Unique string used to identify the operation.
deprecated – Declares this operation to be deprecated. Overrides controller-level and router-level values. Set it to
Falseto explicitly mark this operation as not deprecated, even if its controller or router is.security – A sequence of security requirement objects for this operation. Overrides the controller value and
securityofdmr.openapi.OpenAPIConfig. Set it toNoneto disablesecurityof this endpoint. It is merged with the requirements generated fromauth, but it never affects the runtime auth. Useful to document external security mechanisms, for example, the ones enforced by an HTTP proxy. Used security schemes must be declared assecurity_schemesincomponentsofdmr.openapi.OpenAPIConfig. See Customizing security.external_docs – Additional external documentation for this operation. Overrides the controller value. Set it to
Noneto have no external docs at all.callbacks – A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. Overrides the controller value. Set it to
Noneto have no callbacks at all.servers – An alternative servers sequence to service this operation. Overrides the controller value. Set it to
Noneto have no servers at all.x_extensions – Specification extensions of this operation, keys must start with
x-. Set only on this operation: it is never inherited from or merged withx_extensions, which describes the path item, not its operations.links – Possible links to other OpenAPI operations.
response_description – Description for the generated response object.
ignore_from_spec – If set to
True, this endpoint would not be added to the final OpenAPI spec.extras – Extra settings for custom controllers. See Providing extras for @modify and @validate to learn more.
- Returns:
The same function with
__dmr_payload__payload instance.
Warning
Do not disable
validate_responsesunless this is performance critical for you!Changed in version 0.15.0:
modifyused to be a function, now it is an instance withlazymethod for lazy reusable endpoints.Changed in version 0.16.0: Removed validate_events parameter, added extras parameter instead. This class is now generic and public.
- __call__(*, error_handler: sentinel = EMPTY, status_code: HTTPStatus | sentinel = EMPTY, headers: Mapping[str, NewHeader | HeaderSpec] | Sentinel = EMPTY, cookies: Mapping[str, NewCookie | CookieSpec] | Sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, extra_responses: Sequence[ResponseSpec] | Sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[Never] | sentinel | None = EMPTY, throttling: Sequence[Never] | sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, links: Mapping[str, Link | Reference] | Sentinel = EMPTY, response_description: str | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ModifyAnyCallable[source]#
- __call__(*, error_handler: AsyncErrorHandler | Sentinel = EMPTY, status_code: HTTPStatus | sentinel = EMPTY, headers: Mapping[str, NewHeader | HeaderSpec] | Sentinel = EMPTY, cookies: Mapping[str, NewCookie | CookieSpec] | Sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, extra_responses: Sequence[ResponseSpec] | Sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[AsyncAuth] | Sentinel | None = EMPTY, throttling: Sequence[AsyncThrottle] | Sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, links: Mapping[str, Link | Reference] | Sentinel = EMPTY, response_description: str | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ModifyAsyncCallable
- __call__(*, error_handler: SyncErrorHandler | Sentinel = EMPTY, status_code: HTTPStatus | sentinel = EMPTY, headers: Mapping[str, NewHeader | HeaderSpec] | Sentinel = EMPTY, cookies: Mapping[str, NewCookie | CookieSpec] | Sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, extra_responses: Sequence[ResponseSpec] | Sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[SyncAuth] | Sentinel | None = EMPTY, throttling: Sequence[SyncThrottle] | Sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, links: Mapping[str, Link | Reference] | Sentinel = EMPTY, response_description: str | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ModifySyncCallable
Adds the payload to the endpoint function.
- extras_cls: type[_ExtrasT] | sentinel#
Extras class that this decorator instance supports.
Pass it to create a typed decorator:
ModifyEndpoint(MyExtras). Controllers using such decorator must use the same extras class inextras.
- lazy(provider: _CallableOrClassmethod[_ControllerT, _ModifyDecoratorT]) _ModifyDecoratorT[source]#
Create lazy endpoint for reusable controller definition.
This provides an agile way to customize all the response details, including headers and cookies spec, response status code, OpenAPI metadata and other things.
See Lazy reusable endpoints for the full example.
Added in version 0.15.0.
- dmr.endpoint.modify = ModifyEndpoint(extras_cls=EMPTY)#
Decorator to modify endpoints that return raw model data.
Apply it to change some API parts:
>>> from http import HTTPStatus >>> from dmr import Controller, modify >>> from dmr.plugins.pydantic import PydanticFastSerializer >>> class TaskController(Controller[PydanticFastSerializer]): ... @modify(status_code=HTTPStatus.ACCEPTED) ... def post(self) -> list[int]: ... return [1, 2] # id of tasks you have started
- Parameters:
status_code – Shows status_code in the documentation. When status_code is passed, always use it by default. When not provided, we use smart inference based on the HTTP method name for default returned response.
headers – Shows headers in the documentation. When headers are passed we will add them for the default response.
cookies – Shows cookies in the documentation. When cookies are passed we will add them for the default response.
validate_responses – Do we have to run runtime validation of responses for this endpoint? Customizable via global setting, per controller, and per endpoint. Here we only store the per endpoint information.
exclude_validate_responses – Set of status codes that we don’t validate, even when
validate_responsesis enabled. Useful for errors like500that can be raised from anywhere and that you might not want to describe. Overrides controller and settings values. Set it toNoneto validate all status codes back.semantic_schema – Should we generate any semantic schema for this endpoint?
semantic_responses – Should semantic responses be collected from different providers for this endpoint.
exclude_semantic_responses – Set of semantic responses status codes that user wants to disable. Overrides controller and settings values. Set it to
Noneto enable all semantic responses back.semantic_auth – Should semantic auth be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_auth – Set of semantic security requirements names that should not be collected. Overrides controller and settings values.
extra_responses – Sequence of extra responses that this endpoint can return. Overrides controller and settings values. Set it to
Noneto only use the default response.no_validate_http_spec – Set of http spec validation checks that we disable for this endpoint. Overrides controller and settings values. Set it to
Noneto enable all checks back.error_handler – Callback function to be called when this endpoint faces an exception.
parsers – Sequence of types to be used for this endpoint to parse incoming request’s body. All types must be subtypes of
Parser. Overrides controller and settings values.renderers – Sequence of types to be used for this endpoint to render response’s body. All types must be subtypes of
Renderer. Overrides controller and settings values.validate_negotiation – Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?auth – Sequence of auth instances to be used for this endpoint. Sync endpoints must use instances of
dmr.security.SyncAuth. Async endpoints must use instances ofdmr.security.AsyncAuth. Overrides controller and settings values. Set it toNoneto disable auth for this endpoint.throttling – Sequence of throttle instances to be used for this endpoint. Sync endpoints must use instances of
dmr.throttling.SyncThrottle. Async endpoints must use instances ofdmr.throttling.AsyncThrottle. Overrides controller and settings values. Set it toNoneto disable throttling of this endpoint.summary – A short summary of what the operation does. Defaults to the first paragraph of the endpoint’s docstring. Set it to
Noneto have no summary at all.description – A verbose explanation of the operation behavior. Defaults to everything that goes after the first paragraph of the endpoint’s docstring. Set it to
Noneto have no description at all.tags – A sequence of tags for API documentation control. Used to group operations in OpenAPI documentation. Overrides controller-level and router-level tags. Set it to
Noneto have no tags at all.operation_id – Unique string used to identify the operation.
deprecated – Declares this operation to be deprecated. Overrides controller-level and router-level values. Set it to
Falseto explicitly mark this operation as not deprecated, even if its controller or router is.security – A sequence of security requirement objects for this operation. Overrides the controller value and
securityofdmr.openapi.OpenAPIConfig. Set it toNoneto disablesecurityof this endpoint. It is merged with the requirements generated fromauth, but it never affects the runtime auth. Useful to document external security mechanisms, for example, the ones enforced by an HTTP proxy. Used security schemes must be declared assecurity_schemesincomponentsofdmr.openapi.OpenAPIConfig. See Customizing security.external_docs – Additional external documentation for this operation. Overrides the controller value. Set it to
Noneto have no external docs at all.callbacks – A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. Overrides the controller value. Set it to
Noneto have no callbacks at all.servers – An alternative servers sequence to service this operation. Overrides the controller value. Set it to
Noneto have no servers at all.x_extensions – Specification extensions of this operation, keys must start with
x-. Set only on this operation: it is never inherited from or merged withx_extensions, which describes the path item, not its operations.links – Possible links to other OpenAPI operations.
response_description – Description for the generated response object.
ignore_from_spec – If set to
True, this endpoint would not be added to the final OpenAPI spec.extras – Extra settings for custom controllers. See Providing extras for @modify and @validate to learn more.
- Returns:
The same function with
__dmr_payload__payload instance.
Warning
Do not disable
validate_responsesunless this is performance critical for you!Changed in version 0.15.0:
modifyused to be a function, now it is an instance withlazymethod for lazy reusable endpoints.Changed in version 0.16.0: Removed validate_events parameter, added extras parameter instead. This class is now generic and public.
Validate#
- final class dmr.endpoint.ValidateEndpoint(extras_cls: type[_ExtrasT] | sentinel = EMPTY)[source]#
Decorator to validate responses from endpoints that return
HttpResponse.Apply it to validate important API parts:
>>> from http import HTTPStatus >>> from django.http import HttpResponse >>> from dmr import Controller, validate, ResponseSpec >>> from dmr.plugins.pydantic import PydanticFastSerializer >>> class TaskController(Controller[PydanticFastSerializer]): ... @validate( ... ResponseSpec( ... return_type=list[int], ... status_code=HTTPStatus.OK, ... ), ... ) ... def post(self) -> HttpResponse: ... return HttpResponse(b'[1, 2]', status=HTTPStatus.OK)
Response validation can be disabled for extra speed by sending validate_responses falsy parameter or by setting this configuration in your
settings.pyfile:settings.py#>>> DMR_SETTINGS = {'validate_responses': False}- Parameters:
response – The main response that this endpoint is allowed to return.
responses – A collection of other responses that are allowed to be returned from this endpoint.
validate_responses – Do we have to run runtime validation of responses for this endpoint? Customizable via global setting, per controller, and per endpoint. Here we only store the per endpoint information.
exclude_validate_responses – Set of status codes that we don’t validate, even when
validate_responsesis enabled. Useful for errors like500that can be raised from anywhere and that you might not want to describe. Overrides controller and settings values. Set it toNoneto validate all status codes back.semantic_schema – Should we generate any semantic schema for this endpoint?
semantic_responses – Should semantic responses be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_responses – Set of semantic responses status codes that user wants to disable. Overrides controller and settings values. Set it to
Noneto enable all semantic responses back.semantic_auth – Should semantic auth be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_auth – Set of semantic security requirements names that should not be collected. Overrides controller and settings values.
no_validate_http_spec – Set of http spec validation checks that we disable for this endpoint. Overrides controller and settings values. Set it to
Noneto enable all checks back.error_handler – Callback function to be called when this endpoint faces an exception.
parsers – Sequence of types to be used for this endpoint to parse incoming request’s body. All types must be subtypes of
Parser. Overrides controller and settings values.renderers – Sequence of types to be used for this endpoint to render response’s body. All types must be subtypes of
Renderer. Overrides controller and settings values.validate_negotiation – Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?auth – Sequence of auth instances to be used for this endpoint. Sync endpoints must use instances of
dmr.security.SyncAuth. Async endpoints must use instances ofdmr.security.AsyncAuth. Overrides controller and settings values. Set it toNoneto disable auth for this endpoint.throttling – Sequence of throttle instances to be used for this endpoint. Sync endpoints must use instances of
dmr.throttling.SyncThrottle. Async endpoints must use instances ofdmr.throttling.AsyncThrottle. Overrides controller and settings values. Set it toNoneto disable throttling of this endpoint.summary – A short summary of what the operation does. Defaults to the first paragraph of the endpoint’s docstring. Set it to
Noneto have no summary at all.description – A verbose explanation of the operation behavior. Defaults to everything that goes after the first paragraph of the endpoint’s docstring. Set it to
Noneto have no description at all.tags – A sequence of tags for API documentation control. Used to group operations in OpenAPI documentation. Overrides controller-level and router-level tags. Set it to
Noneto have no tags at all.operation_id – Unique string used to identify the operation.
deprecated – Declares this operation to be deprecated. Overrides controller-level and router-level values. Set it to
Falseto explicitly mark this operation as not deprecated, even if its controller or router is.security – A sequence of security requirement objects for this operation. Overrides the controller value and
securityofdmr.openapi.OpenAPIConfig. Set it toNoneto disablesecurityof this endpoint. It is merged with the requirements generated fromauth, but it never affects the runtime auth. Useful to document external security mechanisms, for example, the ones enforced by an HTTP proxy. Used security schemes must be declared assecurity_schemesincomponentsofdmr.openapi.OpenAPIConfig. See Customizing security.external_docs – Additional external documentation for this operation. Overrides the controller value. Set it to
Noneto have no external docs at all.callbacks – A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. Overrides the controller value. Set it to
Noneto have no callbacks at all.servers – An alternative servers sequence to service this operation. Overrides the controller value. Set it to
Noneto have no servers at all.x_extensions – Specification extensions of this operation, keys must start with
x-. Set only on this operation: it is never inherited from or merged withx_extensions, which describes the path item, not its operations.ignore_from_spec – If set to
True, this endpoint would not be added to the final OpenAPI spec.extras – Extra settings for custom controllers. See Providing extras for @modify and @validate to learn more.
- Returns:
The same function with
__dmr_payload__payload instance.
Warning
Do not disable
validate_responsesunless this is performance critical for you!Changed in version 0.15.0:
validateused to be a function, now it is an instance withlazymethod for lazy reusable endpoints.Changed in version 0.16.0: Removed validate_events parameter, added extras parameter instead. This class is now generic and public.
- __call__(response: ResponseSpec, /, *responses: ResponseSpec, error_handler: sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[Never] | sentinel | None = EMPTY, throttling: Sequence[Never] | sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ValidateAnyCallable[source]#
- __call__(response: ResponseSpec, /, *responses: ResponseSpec, error_handler: AsyncErrorHandler | Sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[AsyncAuth] | Sentinel | None = EMPTY, throttling: Sequence[AsyncThrottle] | Sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ValidateAsyncCallable
- __call__(response: ResponseSpec, /, *responses: ResponseSpec, error_handler: SyncErrorHandler | Sentinel = EMPTY, validate_responses: bool | sentinel = EMPTY, exclude_validate_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_schema: bool | sentinel = EMPTY, semantic_responses: bool | sentinel = EMPTY, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None = EMPTY, semantic_auth: bool | sentinel = EMPTY, exclude_semantic_auth: Set[str] | sentinel | None = EMPTY, no_validate_http_spec: Set[HttpSpec] | Sentinel | None = EMPTY, parsers: Sequence[Parser] | Sentinel = EMPTY, renderers: Sequence[Renderer] | Sentinel = EMPTY, validate_negotiation: bool | sentinel = EMPTY, auth: Sequence[SyncAuth] | Sentinel | None = EMPTY, throttling: Sequence[SyncThrottle] | Sentinel | None = EMPTY, summary: str | Promise | sentinel | None = EMPTY, description: str | Promise | sentinel | None = EMPTY, tags: Sequence[str] | sentinel | None = EMPTY, operation_id: str | sentinel = EMPTY, deprecated: bool | sentinel = EMPTY, security: Sequence[SecurityRequirement] | Sentinel | None = EMPTY, external_docs: ExternalDocumentation | Sentinel | None = EMPTY, callbacks: Mapping[str, Callback | Reference] | Sentinel | None = EMPTY, servers: Sequence[Server] | Sentinel | None = EMPTY, x_extensions: Mapping[str, Any] | sentinel = EMPTY, ignore_from_spec: bool | sentinel = EMPTY, extras: _ExtrasT | sentinel = EMPTY) ValidateSyncCallable
Adds the payload to the endpoint function.
- extras_cls: type[_ExtrasT] | sentinel#
Extras class that this decorator instance supports.
Pass it to create a typed decorator:
ValidateEndpoint(MyExtras). Controllers using such decorator must use the same extras class inextras.
- lazy(provider: _CallableOrClassmethod[_ControllerT, _ValidateDecoratorT]) _ValidateDecoratorT[source]#
Create lazy endpoint for reusable controller definition.
This provides an agile way to customize all the response details, including headers and cookies spec, response status code, OpenAPI metadata and other things.
See Lazy reusable endpoints for the full example.
Added in version 0.15.0.
- dmr.endpoint.validate = ValidateEndpoint(extras_cls=EMPTY)#
Decorator to validate responses from endpoints that return
HttpResponse.Apply it to validate important API parts:
>>> from http import HTTPStatus >>> from django.http import HttpResponse >>> from dmr import Controller, validate, ResponseSpec >>> from dmr.plugins.pydantic import PydanticFastSerializer >>> class TaskController(Controller[PydanticFastSerializer]): ... @validate( ... ResponseSpec( ... return_type=list[int], ... status_code=HTTPStatus.OK, ... ), ... ) ... def post(self) -> HttpResponse: ... return HttpResponse(b'[1, 2]', status=HTTPStatus.OK)
Response validation can be disabled for extra speed by sending validate_responses falsy parameter or by setting this configuration in your
settings.pyfile:settings.py#>>> DMR_SETTINGS = {'validate_responses': False}- Parameters:
response – The main response that this endpoint is allowed to return.
responses – A collection of other responses that are allowed to be returned from this endpoint.
validate_responses – Do we have to run runtime validation of responses for this endpoint? Customizable via global setting, per controller, and per endpoint. Here we only store the per endpoint information.
exclude_validate_responses – Set of status codes that we don’t validate, even when
validate_responsesis enabled. Useful for errors like500that can be raised from anywhere and that you might not want to describe. Overrides controller and settings values. Set it toNoneto validate all status codes back.semantic_schema – Should we generate any semantic schema for this endpoint?
semantic_responses – Should semantic responses be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_responses – Set of semantic responses status codes that user wants to disable. Overrides controller and settings values. Set it to
Noneto enable all semantic responses back.semantic_auth – Should semantic auth be collected from different providers for this endpoint. Overrides controller and settings values.
exclude_semantic_auth – Set of semantic security requirements names that should not be collected. Overrides controller and settings values.
no_validate_http_spec – Set of http spec validation checks that we disable for this endpoint. Overrides controller and settings values. Set it to
Noneto enable all checks back.error_handler – Callback function to be called when this endpoint faces an exception.
parsers – Sequence of types to be used for this endpoint to parse incoming request’s body. All types must be subtypes of
Parser. Overrides controller and settings values.renderers – Sequence of types to be used for this endpoint to render response’s body. All types must be subtypes of
Renderer. Overrides controller and settings values.validate_negotiation – Should we validate that returned response’s
Content-Typeheader matches the one that we inferred in the negotiation process?auth – Sequence of auth instances to be used for this endpoint. Sync endpoints must use instances of
dmr.security.SyncAuth. Async endpoints must use instances ofdmr.security.AsyncAuth. Overrides controller and settings values. Set it toNoneto disable auth for this endpoint.throttling – Sequence of throttle instances to be used for this endpoint. Sync endpoints must use instances of
dmr.throttling.SyncThrottle. Async endpoints must use instances ofdmr.throttling.AsyncThrottle. Overrides controller and settings values. Set it toNoneto disable throttling of this endpoint.summary – A short summary of what the operation does. Defaults to the first paragraph of the endpoint’s docstring. Set it to
Noneto have no summary at all.description – A verbose explanation of the operation behavior. Defaults to everything that goes after the first paragraph of the endpoint’s docstring. Set it to
Noneto have no description at all.tags – A sequence of tags for API documentation control. Used to group operations in OpenAPI documentation. Overrides controller-level and router-level tags. Set it to
Noneto have no tags at all.operation_id – Unique string used to identify the operation.
deprecated – Declares this operation to be deprecated. Overrides controller-level and router-level values. Set it to
Falseto explicitly mark this operation as not deprecated, even if its controller or router is.security – A sequence of security requirement objects for this operation. Overrides the controller value and
securityofdmr.openapi.OpenAPIConfig. Set it toNoneto disablesecurityof this endpoint. It is merged with the requirements generated fromauth, but it never affects the runtime auth. Useful to document external security mechanisms, for example, the ones enforced by an HTTP proxy. Used security schemes must be declared assecurity_schemesincomponentsofdmr.openapi.OpenAPIConfig. See Customizing security.external_docs – Additional external documentation for this operation. Overrides the controller value. Set it to
Noneto have no external docs at all.callbacks – A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a Callback Object that describes a request that may be initiated by the API provider and the expected responses. Overrides the controller value. Set it to
Noneto have no callbacks at all.servers – An alternative servers sequence to service this operation. Overrides the controller value. Set it to
Noneto have no servers at all.x_extensions – Specification extensions of this operation, keys must start with
x-. Set only on this operation: it is never inherited from or merged withx_extensions, which describes the path item, not its operations.ignore_from_spec – If set to
True, this endpoint would not be added to the final OpenAPI spec.extras – Extra settings for custom controllers. See Providing extras for @modify and @validate to learn more.
- Returns:
The same function with
__dmr_payload__payload instance.
Warning
Do not disable
validate_responsesunless this is performance critical for you!Changed in version 0.15.0:
validateused to be a function, now it is an instance withlazymethod for lazy reusable endpoints.Changed in version 0.16.0: Removed validate_events parameter, added extras parameter instead. This class is now generic and public.
Extras#
- class dmr.endpoint.Extras[source]#
Abstract base class that describes how any extras should look like.
Extras are extra settings for custom controllers, they are passed as
extras=to@modifyand@validate. A controller declares which extras it supports by assigning a default instance toextras, the same instance provides controller-level defaults.Fields that can be omitted on some level should default to
EMPTY, required fields are allowed as well.The type parameter is the type of the built value, it is stored in
extrasas the first type variable. Useof()to read it with proper types.Added in version 0.16.0.
- abstractmethod classmethod build(from_endpoint: Self | Sentinel, from_controller: Self, controller_cls: type[Controller[BaseSerializer]], builder: EndpointMetadataBuilder) _BuiltExtrasT_co[source]#
Method that we need to build the final value.
It is called for all endpoints of controllers that support these extras, even when
extras=is not passed to the decorator or when there’s no decorator at all.from_endpoint is the instance passed as
extras=to the decorator, orEMPTYwhen it was not passed. from_controller is the instance set asController.extras, it is always present.We pass controller_cls, so user can take any needed values from there. Or from settings, or from where else. builder provides other context from the whole payload, use
merger()to resolve configuration layers the same way other fields do.The value returned from here will be used in the final metadata. It is called during the import-time and can be slow.
- classmethod of(controller: Controller[BaseSerializer]) _BuiltExtrasT_co[source]#
Get the built extras of the endpoint that serves the current request.
This is the typed way to read
extras. RaisesEndpointMetadataErrorwhen controller does not use these extras.
Lazy endpoints#
- class dmr.endpoint.ModifySyncCallable(*args, **kwargs)[source]#
Type that represents
@modifydecorator for sync functions.Features:
Does not allow using
HttpResponseas the return annotationDoes not allow applying the decorator on async endpoints
- class dmr.endpoint.ModifyAsyncCallable(*args, **kwargs)[source]#
Type that represents
@modifydecorator for async functions.Features:
Does not allow using
HttpResponseas the return annotationDoes not allow applying the decorator on sync endpoints
- class dmr.endpoint.ModifyAnyCallable(*args, **kwargs)[source]#
Type that represents
@modifydecorator for any function.Features:
Does not allow using
HttpResponseas the return annotationDoes not allow specifying sync / async specific parts
- class dmr.endpoint.ValidateSyncCallable(*args, **kwargs)[source]#
Type that represents
@validatedecorator for sync functions.Features:
Does not allow using anything other than
HttpResponseas the return annotationDoes not allow applying the decorator on async endpoints
Added in version 0.15.0.
Validation#
- final class dmr.validation.ModifyEndpointPayload(*, summary: str | Promise | sentinel | None, description: str | Promise | sentinel | None, tags: Sequence[str] | sentinel | None, operation_id: str | sentinel, deprecated: bool | sentinel, security: Sequence[SecurityRequirement] | sentinel | None, external_docs: ExternalDocumentation | Sentinel | None, callbacks: Mapping[str, Callback | Reference] | sentinel | None, servers: Sequence[Server] | sentinel | None, x_extensions: Mapping[str, Any] | sentinel, ignore_from_spec: bool | sentinel, extras: Extras[Any] | Sentinel, extras_cls: type[Extras[Any]] | Sentinel, validate_responses: bool | sentinel, exclude_validate_responses: Set[HTTPStatus] | sentinel | None, semantic_schema: bool | sentinel, semantic_responses: bool | sentinel, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None, semantic_auth: bool | sentinel, exclude_semantic_auth: Set[str] | sentinel | None, error_handler: Callable[[Endpoint, Controller[BaseSerializer], Exception], HttpResponse] | Callable[[Endpoint, Controller[BaseSerializer], Exception], Awaitable[HttpResponse]] | sentinel, no_validate_http_spec: Set[HttpSpec] | sentinel | None, parsers: Sequence[Parser] | sentinel, renderers: Sequence[Renderer] | sentinel, validate_negotiation: bool | sentinel, auth: Sequence[SyncAuth] | Sequence[AsyncAuth] | sentinel | None, throttling: Sequence[SyncThrottle] | Sequence[AsyncThrottle] | sentinel | None, responses: Sequence[ResponseSpec] | sentinel | None, status_code: HTTPStatus | sentinel, headers: Mapping[str, NewHeader | HeaderSpec] | sentinel, cookies: Mapping[str, NewCookie | CookieSpec] | sentinel, response_description: str | sentinel, links: Mapping[str, Link | Reference] | sentinel)[source]#
Payload created by
@modify.
- final class dmr.validation.ValidateEndpointPayload(*, summary: str | Promise | sentinel | None, description: str | Promise | sentinel | None, tags: Sequence[str] | sentinel | None, operation_id: str | sentinel, deprecated: bool | sentinel, security: Sequence[SecurityRequirement] | sentinel | None, external_docs: ExternalDocumentation | Sentinel | None, callbacks: Mapping[str, Callback | Reference] | sentinel | None, servers: Sequence[Server] | sentinel | None, x_extensions: Mapping[str, Any] | sentinel, ignore_from_spec: bool | sentinel, extras: Extras[Any] | Sentinel, extras_cls: type[Extras[Any]] | Sentinel, validate_responses: bool | sentinel, exclude_validate_responses: Set[HTTPStatus] | sentinel | None, semantic_schema: bool | sentinel, semantic_responses: bool | sentinel, exclude_semantic_responses: Set[HTTPStatus] | sentinel | None, semantic_auth: bool | sentinel, exclude_semantic_auth: Set[str] | sentinel | None, error_handler: Callable[[Endpoint, Controller[BaseSerializer], Exception], HttpResponse] | Callable[[Endpoint, Controller[BaseSerializer], Exception], Awaitable[HttpResponse]] | sentinel, no_validate_http_spec: Set[HttpSpec] | sentinel | None, parsers: Sequence[Parser] | sentinel, renderers: Sequence[Renderer] | sentinel, validate_negotiation: bool | sentinel, auth: Sequence[SyncAuth] | Sequence[AsyncAuth] | sentinel | None, throttling: Sequence[SyncThrottle] | Sequence[AsyncThrottle] | sentinel | None, responses: list[ResponseSpec] | sentinel)[source]#
Payload created by
@validate.- classmethod implicit() ValidateEndpointPayload[source]#
Create a payload for endpoints that return
HttpResponse.Such endpoints do not have to use
@validateexplicitly, when responses are defined on the controller or settings level. All values are the same as@validatedefaults, exceptresponseswhich isEMPTYand not an explicit[], so the controller and settings levels are used.
- class dmr.validation.payload.PayloadBuilder(func: Callable[[...], Any])[source]#
Builds the payload from the endpoint function and the controller class.
Added in version 0.15.0.
- __call__(controller_cls: type[Controller[BaseSerializer]]) ValidateEndpointPayload | ModifyEndpointPayload | None[source]#
Processes the callable payloads from
modify.lazyand others.
Serialization#
- class dmr.serializer.BaseSerializer[source]#
Abstract base class for data serialization.
What serializer does?
It provides serialization and deserialization hooks for parser and renderer. So different parsers and renderers will work similarly. This way you can modify all the serialization logic in one place and not adjust all possible parsers or renderers
It provides validation for raw python data, see
dmr.serializer.BaseSerializer.from_python()methodIt provides serialization for related complex utility objects like validation errors and responses that don’t have
.contentattribute. For example: file and sse responses
- validation_error#
Exception type that is used for validation errors. Required to be set in subclasses.
- optimizer#
Endpoint optimizer. Type that pre-compiles / creates / caches models in import time. Required to be set in subclasses.
- Type:
ClassVar[type[dmr.serializer.BaseEndpointOptimizer]]
- schema_generator#
Generates schema and schema names for the OpenAPI.
- Type:
ClassVar[type[dmr.serializer.BaseSchemaGenerator]]
- abstractmethod classmethod build_context_model(name: str, fields: Mapping[str, ContextField]) ContextModel[source]#
Build the best model to parse the whole request context at once.
All components of an endpoint are parsed in a single
from_python()call. This method builds the model for that call. Each serializer picks the fastest model type it can validate: it can be atyping.TypedDict, a dataclass, amsgspec.Struct, or anything else.Fields with defaults must not be required by the model. Default values must be used as-is, without any copies or default factories, because they are the real python defaults of the endpoint function. Use
context_field_tuples()to get them in the form that most model constructors accept.- Parameters:
name – Name of the model to build. Not really important.
fields – Mapping of field names to their annotations and defaults.
- Returns:
Model and the way to convert its instances into keyword arguments.
Added in version 0.16.0.
- abstractmethod classmethod deserialize(buffer: bytes | bytearray, *, parser: Parser, request: HttpRequest, model: Any) Any[source]#
Convert json bytestring to structured data.
- classmethod deserialize_hook(target_type: type[Any], to_deserialize: Any) Any[source]#
Customize how some objects are deserialized from json.
Only add types that are common for all potential plugins here. Should be called inside
deserialize().
- abstractmethod classmethod from_python(unstructured: Any, model: Any, *, strict: bool | None, extra_namespace: Mapping[str, Any] | None = None) Any[source]#
Parse unstructured data from python primitives into model.
Raises
cls.validation_errorwhen something cannot be parsed.- Parameters:
unstructured – Python objects to be parsed / validated.
model – Python type to serve as a model. Can be any type hints that user can theoretically supply. Depends on the serialization plugin.
strict – Whether we use more strict validation rules. For example, it is fine for a request validation to be less strict in some cases and allow type coercition. But, response types need to be strongly validated.
extra_namespace – Optional namespace to load type annotations from. It is useful, when using stringified or lazy type annotations.
- Returns:
Structured and validated data.
Changed in version 0.13.0: Added extra_namespace parameter.
- abstractmethod classmethod serialize(structure: Any, *, renderer: Renderer) bytes[source]#
Convert structured data to json bytestring.
- classmethod serialize_hook(to_serialize: Any) Any[source]#
Customize how some objects are serialized into json.
Only add types that are common for all potential plugins here. Should be called inside
serialize().
- abstractmethod classmethod serialize_validation_error(exc: Exception) list[ErrorDetail][source]#
Convert specific serializer’s validation errors into simple python data.
- Parameters:
exc – A serialization exception to be serialized into simpler type. For example, pydantic has a complex
pydantic_core.ValidationErrortype. That can’t be converted to a simpler error message easily.- Returns:
Simple python object - exception converted to json.
- abstractmethod classmethod to_python(structured: Any) Any[source]#
Unstructure structured data from a model into Python primitives.
- Parameters:
structured – Model instance.
- Returns:
Unstructured data.
- classmethod validate(controller_cls: type[Controller[BaseSerializer]], metadata: EndpointMetadata) None[source]#
Validate that this serializer can serve the endpoint at import time.
It is called once per endpoint, after all metadata fields are fully built, so parsers, renderers, components, and everything else can be inspected. Override this method to enforce serializer-specific constraints, like supported parsers and renderers or supported components. Raise
EndpointMetadataErrorif the serializer is used incorrectly.By default all endpoints are supported.
Changed in version 0.16.0: Replaces
is_supportedmethod, which only received a single parser or renderer and returned a boolean.
- class dmr.serializer.BaseEndpointOptimizer[source]#
Plugins might often need to run some specific preparations for endpoints.
To achieve that we provide an explicit API for that.
- abstractmethod classmethod optimize_endpoint(metadata: EndpointMetadata) None[source]#
Optimize the endpoint.
- Parameters:
metadata – Endpoint metadata to optimize.
- class dmr.endpoint.SerializerContext(func: Callable[[...], Any], controller_cls: type[Controller[BaseSerializer]], type_annotations: dict[str, Any])[source]#
Parse and bind request components for a controller.
This context collects raw data for all registered components, validates the combined payload in a single call using a cached model that the serializer builds, and then binds the parsed values back to the controller.
Components with default values return them when a request has no data for them, so the endpoint receives their real python defaults.
- strict_validation#
Whether or not to validate payloads in strict mode. Strict mode in some serializers does not allow implicit type conversions. Defaults to
None, which means that we decide on a per-field basis if it is set, if not then on a per-model basis.- Type:
ClassVar[bool | None]
Changed in version 0.16.0: Models are now built by
serializer.build_context_model, defaults of component parameters are now supported.- __call__(endpoint: Endpoint, controller: Controller[BaseSerializer]) dict[str, Any][source]#
Collect, validate, and bind component data to the controller.
Raises
serializer.validation_errorwhen provided data does not match the expected model.
- component_builder_cls#
alias of
ComponentParserBuilder
- class dmr.serializer.BaseSchemaGenerator[source]#
Generates JSON schema by the native serializer API.
- final class dmr.serializer.ContextField(annotation: Any, default: Any = EMPTY)[source]#
Single field of a context model to be built by a serializer.
Added in version 0.16.0.
- final class dmr.serializer.ContextModel(model: Any, to_kwargs: Callable[[Any], dict[str, Any]] | None = None)[source]#
Model that a serializer has built to parse the whole request context.
Added in version 0.16.0.
- model: Any#
Any type that
BaseSerializer.from_python()can parse into.
- dmr.serializer.context_field_tuples(fields: Mapping[str, ContextField]) list[tuple[Any, ...]][source]#
Convert context fields into tuples that model constructors accept.
Both
dataclasses.make_dataclass()andmsgspec.defstruct()accept(name, type)tuples for required fields and(name, type, default)tuples for fields with defaults. Fields with defaults always go after the fields without them, just like in regular function signatures.Added in version 0.16.0.
- class dmr.components.ComponentParserBuilder(func: Callable[[...], Any], controller_cls: type[Controller[BaseSerializer]])[source]#
Find the component parser types in the MRO and find model types for them.
Validates that component parsers can’t have type vars as models at this point.
Changed in version 0.16.0: Now also finds default values of component parameters. Component annotations hidden inside other types, like
Body[Model] | None, are now rejected.- __call__(type_annotations: dict[str, Any]) list[ComponentParserSpec][source]#
Run the building process, infer type vars if needed.
- defaults_cls#
alias of
FunctionDefaults
- type_var_inference_cls#
alias of
TypeVarInference
- final class dmr.components.ComponentParserSpec(parser: ComponentParser, model: Any, model_meta: tuple[Any, ...], default: Any = EMPTY)[source]#
Describes a single component parser of an endpoint.
Changed in version 0.16.0: Now it is a named tuple with the default field, previously it was a regular tuple of three elements. Moved from
dmr.metadatatodmr.components.- default: Any#
Default value of the endpoint parameter for this component.
EMPTYmeans that there’s no default value, so the component data must be present in every request.
- model_meta: tuple[Any, ...]#
Extra
typing.Annotatedmetadata of the component.
- parser: ComponentParser#
Component parser instance, like
BodyComponent.
- class dmr.components.FunctionDefaults(func: Callable[[...], Any])[source]#
Find default values of all function parameters.
Both regular and keyword-only defaults are supported. Component parameters with defaults are optional: when a request has no data for such a component, the default value is used as-is, without any parsing.
Added in version 0.16.0.
Routing#
- class dmr.routing.Router(prefix: str = '', urls: Iterable[URLPattern | URLResolver] = (), *, tags: Sequence[str] | None = None, deprecated: bool = False, ignore_from_spec: bool = False)[source]#
Collection of HTTP routes for REST framework.
- prefix#
URL prefix for all routes (e.g., ‘api/v1/’). Defaults to empty string
''.
- urls#
Sequence of URL patterns and resolvers.
- tags#
Optional sequence of tags to group operations in OpenAPI. Used for operations that do not have controller-level or endpoint-level tags.
- deprecated#
Optional flag to mark all operations as deprecated. Used for operations that do not have controller-level or endpoint-level
deprecatedvalue.
- ignore_from_spec#
If set to
True, all routes from this router are excluded from the generated OpenAPI specification. Runtime URL routing is not affected.
Note
tags and deprecated is not applied to external urls’ metadata. It is always included as-is.
Changed in version 0.7.0: Added tags and deprecated parameters.
Changed in version 0.13.0: Now you can pass
external_path()objects in urls. Also accept anycollections.abc.Sequenceas tags. urls parameter is now optional.Changed in version 0.15.0: Added ignore_from_spec parameter.
- get_schema(context: OpenAPIContext) OpenAPI[source]#
Builds OpenAPI specification.
This class orchestrates the process of generating a complete OpenAPI specification by collecting controllers from the router, generating path items for each controller, extracting shared components, and merging everything together with the configuration.
- include(router: Router, *, namespace: str | None = None, app_name: str | None = None) None[source]#
Include a router’s URLs under a given app name and namespace.
Added in version 0.13.0.
- metadata_for(openapi_path: str) RouterMetadata[source]#
Returns applied nested metadata from all router layers.
- Raises:
KeyError – if openapi_path is not found.
Added in version 0.15.0.
- to_urlpatterns(*, namespace: str | None = None, app_name: str | None = None) URLResolver[source]#
Convert router instance into
urlpatternsinclude API.Can be used to include one router into another. Or to include a router into the final
urlpatternslist.Automatically uses our own faster
path()function.Added in version 0.14.0.
- dmr.routing.build_404_handler(prefix: str, /, *prefixes: str, serializer: type[BaseSerializer], format_error: ~dmr.internal.types.FormatError = <function format_error>, renderers: ~collections.abc.Sequence[Renderer] | None = None) Callable[[HttpRequest, Exception], HttpResponse][source]#
Create a 404 handler that returns a response with content negotiation.
All prefixes are normalized to start with a leading slash. If the request path matches any of them, a 404 response is returned using the same serializer and renderers as your API. If the client’s
Acceptdoes not match any renderer, the first configured renderer is used. For non-matching paths, Django’s defaultpage_not_foundhandler is used.- Parameters:
prefix – Path prefix (e.g.
'api/') for which to return API 404.*prefixes – Additional path prefixes.
format_error – Callable used to build the error body for the response.
serializer – Serializer class used to serialize the error body.
renderers – Optional sequence of renderers. If omitted, uses
renderersfrom settings.
- dmr.routing.build_500_handler(prefix: str, /, *prefixes: str, serializer: type[BaseSerializer], format_error: ~dmr.internal.types.FormatError = <function format_error>, renderers: ~collections.abc.Sequence[Renderer] | None = None) Callable[[HttpRequest], HttpResponse][source]#
Create a 500 handler that returns a response with content negotiation.
All prefixes are normalized to start with a leading slash. If the request path matches any of them, a 500 response is returned using the same serializer and renderers as your API. If the client’s
Acceptdoes not match any renderer, the first configured renderer is used. For non-matching paths, Django’s defaultserver_errorhandler is used.- Parameters:
prefix – Path prefix (e.g.
'api/') for which to return API 500.*prefixes – Additional path prefixes.
format_error – Callable used to build the error body for the response.
serializer – Serializer class used to serialize the error body.
renderers – Optional sequence of renderers. If omitted, uses
renderersfrom settings.
- dmr.routing.path(route: str | Promise, view: Callable[[...], HttpResponseBase | Coroutine[Any, Any, HttpResponseBase]], kwargs: dict[str, Any] | None = None, name: str | None = None) URLPattern[source]#
- dmr.routing.path(route: str | Promise, view: tuple[Sequence[URLPattern | URLResolver], str | None, str | None], kwargs: dict[str, Any] | None = None, name: str | None = None) URLResolver
- dmr.routing.path(route: str | Promise, view: Sequence[URLResolver | str], kwargs: dict[str, Any] | None = None, name: str | None = None) URLResolver
Creates URL pattern using prefix-based matching for faster routing.
- dmr.routing.external_path(route: str | Promise, view: Callable[[...], HttpResponseBase | Coroutine[Any, Any, HttpResponseBase]], *, openapi: PathItem | None, kwargs: dict[str, Any] | None = None, name: str | None = None) URLPattern[source]#
Add an external path onto the DMR routing system.
Automatically uses our own faster
path()function.- Parameters:
route – String route for the view.
view – Function or class view, supports both sync and async callables.
openapi – OpenAPI metadata to show in the spec. Or
Noneto hide this endpoint.kwargs – Init kwargs for the view.
name – Name to resolve this URL.
See External views for more info.
Added in version 0.13.0.
Changed in version 0.16.0: Now it can be nested anywhere in the
Routerurls tree.
- dmr.routing.external_re_path(route: str | Promise, view: Callable[[...], HttpResponseBase | Coroutine[Any, Any, HttpResponseBase]], *, openapi: PathItem | None, kwargs: dict[str, Any] | None = None, name: str | None = None) URLPattern[source]#
Add an external path onto the DMR routing system.
- Parameters:
route – String route for the view.
view – Function or class view, supports both sync and async callables.
openapi – OpenAPI metadata to show in the spec. Or
Noneto hide this endpoint.kwargs – Init kwargs for the view.
name – Name to resolve this URL.
See External views for more info.
Added in version 0.16.0.
Meta mixins#
- class dmr.options_mixins.MetaMixin[source]#
Mixin that provides default
metamethod orOPTIONShttp method.Use it for sync controllers.
It just returns the list of allowed methods. Use it as a mixin with the
dmr.controller.Controllertype:>>> from dmr import Controller >>> from dmr.options_mixins import MetaMixin >>> from dmr.plugins.pydantic import PydanticSerializer >>> class SupportsOptionsHttpMethod( ... MetaMixin, ... Controller[PydanticSerializer], ... ): ...
- meta() HttpResponse[source]#
Default sync implementation for
OPTIONShttp method.
- class dmr.options_mixins.AsyncMetaMixin[source]#
Mixin that provides default
metamethod orOPTIONShttp method.Use it for async controllers.
It just returns the list of allowed methods. Use it as a mixin with the
dmr.controller.Controllertype:>>> from dmr import Controller >>> from dmr.options_mixins import AsyncMetaMixin >>> from dmr.plugins.pydantic import PydanticSerializer >>> class SupportsOptionsHttpMethod( ... AsyncMetaMixin, ... Controller[PydanticSerializer], ... ): ...
- async meta() HttpResponse[source]#
Default async implementation for
OPTIONShttp method.
Exceptions#
- final exception dmr.exceptions.UnsolvableAnnotationsError[source]#
Bases:
ExceptionRaised when we can’t solve function’s annotations using
get_type_hints.Only raised when there are no other options.
- final exception dmr.exceptions.EndpointMetadataError[source]#
Bases:
ExceptionRaised when user didn’t specify some required endpoint metadata.
- final exception dmr.exceptions.DataParsingError[source]#
Bases:
ExceptionRaised when input data cannot be parsed.
- final exception dmr.exceptions.RequestSerializationError[source]#
Bases:
ExceptionRaised when we fail to parse some request part.
- final exception dmr.exceptions.ResponseSchemaError[source]#
Bases:
ExceptionRaised when we fail to validate some response part.
Can only happen when response validation is enabled. Does not show up in the response schema if validation is disabled.
- final exception dmr.exceptions.ValidationError(payload: list[ErrorDetail], *, status_code: HTTPStatus = HTTPStatus.UNPROCESSABLE_ENTITY)[source]#
Bases:
ExceptionRaised when we cannot properly validate request or response models.
It should be only raised when serializer raise its internal validation error.
It is an universal way of handling validation errors from different serializers.
- final exception dmr.exceptions.NotAcceptableError[source]#
Bases:
ExceptionRaised when client provides wrong
Acceptheader.
- final exception dmr.exceptions.NotAuthenticatedError(msg: str | Promise | None = None, *, headers: dict[str, str] | None = None)[source]#
Bases:
ExceptionRaised when we fail to authenticate a user.
Utilities#
- dmr.types.Json: TypeAlias = typing.Any#
Recursive type alias for JSON data.
What is JSON? Integers, floats, booleans, strings, list of them and dicts of them, which keys are always strings.
In runtime it is always
typing.Anybecause of the parsing complexity, while in type checking it correctly defined.We don’t recommend using it for anything serious, it is better to define real models instead.
- dmr.types.EMPTY = EMPTY#
Create a unique sentinel object.
name should be the name of the variable to which the return value shall be assigned.
- class dmr.types.AnnotationsContext(*, globalns: Mapping[str, Any] | None = None, localns: Mapping[str, Any] | None = None, include_extras: bool = True, format: Format | None = None)[source]#
Annotation evaluation context.
Use this type to change how controllers resolve type hints of their endpoints.
For example, one can change this function to use
inspect.get_annotations()function. Or to have some pre-defined global names.- __call__(endpoint_func: Callable[[...], Any]) dict[str, Any][source]#
Get the annotations.
- Parameters:
endpoint_func – function with return type annotation.
- Returns:
Function’s parsed and solved return type. Type aliases are unwrapped, so all the callers can work with real types and their metadata.
- Raises:
UnsolvableAnnotationsError – when annotation can’t be solved or when the annotation does not exist.
- class dmr.types.TypeVarInference(to_infer: TypeVar, context: type[Any])[source]#
Inferences type variables to the applied real type values.
Changed in version 0.16.0: PEP 696 type var defaults are now used when the inheritance chain does not provide a real type value.
- dmr.types.safe_typevar(typevar_name: str, *, stacklevel: int = 1, globalns: dict[str, Any] | None = None) Any[source]#
Typing utility to allow passing
typing.TypeVarsafely.By default
mypyand other type-checkers would raise a typing error on a code like this:>>> from typing import TypeVar >>> from http import HTTPStatus >>> from dmr import validate, ResponseSpec >>> _ModelT = TypeVar('_ModelT') >>> validate( ... ResponseSpec( ... # In traditional Python typing spec, it is not allowed ... # to use type var in this context: ... _ModelT, # type: ignore[misc] ... status_code=HTTPStatus.OK, ... ), ... ) <function ...>
But, this function can help with this problem with no type errors:
>>> validate( ... ResponseSpec( ... safe_typevar('_ModelT'), ... status_code=HTTPStatus.OK, ... ), ... ) <function ...>
- Parameters:
typevar_name – TypeVar name to find in the globals.
stacklevel – Levels of function frames to get globals from.
globalns – Explicit
globalsnamespace. Has a higher priority than stacklevel.
- Raises:
KeyError – If typevar_name is not found in globalns.
Added in version 0.14.0.
Decorators#
- dmr.decorators.dispatch_decorator(func: Callable[[...], Any]) Callable[[_TypeT], _TypeT][source]#
Special helper to decorate class-based view’s
dispatchmethod.Use it directly on controllers, like so:
>>> from dmr import Controller >>> from dmr.decorators import dispatch_decorator >>> from dmr.plugins.pydantic import PydanticSerializer >>> from django.contrib.auth.decorators import login_required >>> @dispatch_decorator(login_required()) ... class MyController(Controller[PydanticSerializer]): ... def get(self) -> str: ... return 'Logged in!'
In this example we would require all calls to all methods of
MyControllerto require an existing authentication.It also works for things like: -
django.contrib.auth.decorators.login_not_required()-django.contrib.auth.decorators.user_passes_test()-django.contrib.auth.decorators.permission_required()- and any other default or custom django decoratorDanger
This will return non-json responses, without respecting your spec! Use with caution!
If you want full spec support, use middleware wrappers. You would probably want to use
wrap_middleware()as well. Or useendpoint_decorator().
- dmr.decorators.endpoint_decorator(original_decorator: Callable[[_ViewT], _ViewT]) Callable[[Callable[[_ParamT], _ReturnT]], Callable[[_ParamT], _ReturnT]][source]#
Apply regular Django-styled decorator to a single endpoint.
Use it with “raw” endpoints that return regular data, not
django.http.HttpResponse.Basically, all endpoints that can be decorated with
modify().Example:
>>> from http import HTTPStatus >>> from dmr import Controller, HeaderSpec, modify >>> from dmr.decorators import endpoint_decorator >>> from dmr.plugins.pydantic import PydanticSerializer >>> from django.contrib.auth.decorators import login_required >>> class MyController(Controller[PydanticSerializer]): ... @endpoint_decorator(login_required()) ... @modify( ... extra_responses=[ ... ResponseSpec( ... None, ... status_code=HTTPStatus.FOUND, ... headers={'Location': HeaderSpec()}, ... ), ... ], ... ) ... def get(self) -> str: ... return 'Logged in!'
It also works for things like: -
django.contrib.auth.decorators.login_not_required()-django.contrib.auth.decorators.user_passes_test()-django.contrib.auth.decorators.permission_required()-django.views.decorators.debug.sensitive_post_parameters()- and any other default or custom django decoratorWarning
Be careful with decorators that you apply. They will not escape the response validation, but will return unmodified responses from the original decorators.
For example:
login_requiredwill return a redirect. You can describe it with the extra metadata.
- dmr.decorators.wrap_middleware(middleware: Callable[[Callable[[...], Any]], Callable[[...], Any]], response: ResponseSpec, *responses: ResponseSpec) Callable[[Callable[[HttpResponse], HttpResponse]], DecoratorWithResponses][source]#
Factory function that creates a decorator with pre-configured middleware.
This allows creating reusable decorators with specific middleware and response handling.
- Parameters:
middleware – Django middleware to apply
response – ResponseSpec for the middleware response
responses – Others ResponseSpec
- Returns:
A function that takes a converter and returns a class decorator
>>> from django.views.decorators.csrf import csrf_protect >>> from django.http import HttpResponse >>> from http import HTTPStatus >>> from dmr import Controller, ResponseSpec >>> from dmr.response import build_response >>> from dmr.plugins.pydantic import PydanticSerializer >>> from dmr.errors import ErrorType, ErrorModel, format_error >>> @wrap_middleware( ... csrf_protect, ... ResponseSpec( ... return_type=ErrorModel, ... status_code=HTTPStatus.FORBIDDEN, ... ), ... ) ... def csrf_protect_json(response: HttpResponse) -> HttpResponse: ... return build_response( ... PydanticSerializer, ... raw_data=format_error( ... 'CSRF verification failed. Request aborted.', ... error_type=ErrorType.user_msg, ... ), ... status_code=HTTPStatus(response.status_code), ... ) >>> @csrf_protect_json ... class MyController(Controller[PydanticSerializer]): ... responses = [ ... *csrf_protect_json.responses, ... ] ... ... def post(self) -> dict[str, str]: ... return {'message': 'ok'}
Security#
CSRF#
- class dmr.security.csrf.CSRFSemanticSchemaProvider(*, error_model: Any = <class 'dmr.errors.ErrorModel'>, status_code: HTTPStatus | None = None, description: str | Promise | None = None, security_scheme_name: str = 'csrf', safe_http_methods: Set[HTTPMethod] = frozenset({<HTTPMethod.GET>, <HTTPMethod.HEAD>, <HTTPMethod.OPTIONS>, <HTTPMethod.TRACE>}))[source]#
Provide response specs for controllers that have
csrf_exempt = False.Only provides response specs for controllers that set explicit
csrf_exempt = Falsesetting and define non-safe HTTP endpoints, likepostorput.Should be added to
dmr.settings.Settings.semantic_schema_providerssetting.- error_model#
Error model to be returned. Since CSRF is executed in a middleware before any controller, we can’t get the error model from a controller. This is why this has to be configured separately.
- Type:
Any
- status_code#
Status code that should be set for failed CSRF responses.
- Type:
http.HTTPStatus | None
- description#
Human readable description, what the response is for.
- Type:
str | django.utils.functional.Promise | None
- safe_http_methods#
Set of secure HTTP method names.
Warning
We can’t possibly detect if CSRF enabled for any controller or not. There can be custom middleware, decorators like
@csrf_protect, or evenensure_csrf()inline calls.So, if you know that CSRF is disabled and still want to use
csrf_exempt = Falsefor some reason (?), disable this provider from settings.Added in version 0.16.0.
- merge_security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], own_requirements: list[dict[str, list[str]]], auth_requirements: list[dict[str, list[str]]]) list[dict[str, list[str]]][source]#
Joins CSRF requirement with each auth requirement.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec][source]#
Returns response specs for CSRF endpoints.
- security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) list[dict[str, list[str]]][source]#
Provides a security schema usage requirement.
- security_schemes(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) dict[str, SecurityScheme | Reference][source]#
Provides a security schema definition.
- dmr.security.csrf.build_csrf_handler(prefix: str, /, *prefixes: str, serializer: type[BaseSerializer], format_error: ~dmr.internal.types.FormatError = <function format_error>, renderers: ~collections.abc.Sequence[Renderer] | None = None, status_code: ~http.HTTPStatus = HTTPStatus.FORBIDDEN) _CSRFViewProtocol[source]#
Create a CSRF error handler that returns a response with negotiation.
Use this function to build
CSRF_FAILURE_VIEWhandler insettings.py.All prefixes are normalized to start with a leading slash. If the request path matches any of them, a REST response is returned using the same serializer and renderers as your API. If the client’s
Acceptdoes not match any renderer, the first configured renderer is used. For non-matching paths, Django’s defaultCSRF_FAILURE_VIEWhandler is used.- Parameters:
prefix – Path prefix (e.g.
'api/') for which to return API responses.*prefixes – Additional path prefixes.
format_error – Callable used to build the error body for the response.
serializer – Serializer class used to serialize the error body.
renderers – Optional sequence of renderers. If omitted, uses
renderersfrom settings.status_code – Status code to be returned. Defaults to
403.
Added in version 0.16.0.
- dmr.security.csrf.csrf_message(reason: str) str[source]#
Return CSRF failure message according the security rules.
Added in version 0.16.0.
- dmr.security.csrf.csrf_response_spec(*, return_type: Any, status_code: HTTPStatus | None = None, description: str | Promise | None = None) ResponseSpec[source]#
Response spec for CSRF error.
Added in version 0.16.0.
- dmr.security.csrf.csrf_security_scheme() SecurityScheme[source]#
Build the security scheme that describes how CSRF is checked.
By default Django keeps the CSRF secret in the
CSRF_COOKIE_NAMEcookie, so the scheme is anapiKeyincookie.With
CSRF_USE_SESSIONS = TrueDjango requires to send CSRF in a header. The session cookie itself is not part of this scheme, it is described by the auth that reads it, for exampleDjangoSessionSyncAuth.Added in version 0.16.0.
- class dmr.security.csrf.CSRFAuthMixin[source]#
Shared parts of auth classes that are protected by CSRF.
This mixin does all of it. Subclasses only have to:
set
security_scheme_nameandcsrf_scheme_nameattributes,implement
auth_security_scheme()with their own scheme,call
_ensure_csrffrom__call__at the right moment.
Must be listed before the concrete auth base in the class bases, so the methods here win over the default ones.
Added in version 0.16.0.
- abstractmethod auth_security_scheme() SecurityScheme[source]#
Provides the security scheme of the auth itself, without CSRF.
- csrf_security_scheme() SecurityScheme[source]#
Provides the security scheme of the CSRF.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec][source]#
Declares extra responses for failed auth and failed CSRF checks.
- security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) list[dict[str, list[str]]][source]#
Requires the auth scheme and CSRF for unsafe HTTP methods.
- security_schemes(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) dict[str, SecurityScheme | Reference][source]#
Provides the auth security scheme together with the CSRF one.
Semantic schema#
- class dmr.semantic_schema.SecurityProvider[source]#
Provides security schemes and security requirements.
Added in version 0.16.0.
- abstractmethod security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) list[SecurityRequirement][source]#
Provides a security schema usage requirement.
- abstractmethod security_schemes(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) dict[str, SecurityScheme | Reference][source]#
Provides a security schema definition.
- class dmr.semantic_schema.ResponseValidationSpecProvider(*, status_code: HTTPStatus = HTTPStatus.UNPROCESSABLE_ENTITY, description: str | Promise | None = 'Raised when returned response does not match the response schema')[source]#
Provide response specs for response schema validation.
Does not add itself for endpoints that have
validate_responsesturned off.Should be added to
dmr.settings.Settings.semantic_schema_providerssetting.- status_code#
Status code to be returned when validation error happens.
- Type:
- description#
Response spec description for humans.
- Type:
str | django.utils.functional.Promise | None
Added in version 0.16.0.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec][source]#
Provides responses that can happen when returning invalid data.
- class dmr.semantic_schema.SecurityRequirementMerger[source]#
Interface for things that can merge security requirements.
What can do that?
security_mergermerges user providedsecurityrequirements with the ones generated fromauthSemantic schema providers merge their own requirements with the ones generated from
auth, likeCSRFSemanticSchemaProviderdoes
Added in version 0.16.0.
- abstractmethod merge_security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], own_requirements: list[SecurityRequirement], auth_requirements: list[SecurityRequirement]) list[SecurityRequirement][source]#
Merge own security requirements into the auth requirements.
This can implement both
ORandANDlogic depending on the security logic: several alternative requirements meanOR, several schemes in a single requirement meanAND.- Parameters:
metadata – Metadata of the endpoint that is being generated.
controller_cls – Controller class of this endpoint.
own_requirements – Requirements of the thing that merges, for example, user provided
security.auth_requirements – Requirements generated from
auth, already processed by semantic schema providers.
- Returns:
The final list of security requirements for the operation.
- class dmr.semantic_schema.OrSecurityRequirementMerger[source]#
Merge security requirements as alternatives.
All requirements are used as-is, own requirements are added after the auth ones. A client can satisfy any of them, this is what
ORmeans in OpenAPI.This is the default value of
security_merger.- Raises:
EndpointMetadataError – When the same requirement is present more than once in the result. It usually means that
securityrepeats whatauthalready documents.
Added in version 0.16.0.
- merge_security_requirements(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], own_requirements: list[SecurityRequirement], auth_requirements: list[SecurityRequirement]) list[SecurityRequirement][source]#
Add own requirements as alternatives to the auth ones.
Testing#
- class dmr.test.DMRRequestFactory(*, json_encoder=<class 'django.core.serializers.json.DjangoJSONEncoder'>, headers=None, query_params=None, **defaults)[source]#
Test utility for testing apps using
django-modern-rest.Based on
django.test.RequestFactory. See their docs for advanced usage: https://docs.djangoproject.com/en/dev/topics/testing/toolsThis type, in contrast to a regular
RequestFactory, setscontent-typeasapplication/json.Sets WSGI environment.
- class dmr.test.DMRAsyncRequestFactory(*, json_encoder=<class 'django.core.serializers.json.DjangoJSONEncoder'>, headers=None, query_params=None, **defaults)[source]#
Version of
DMRRequestFactorybut for ASGI environment.Uses the exactly the same API.
- class dmr.test.DMRClient(enforce_csrf_checks=False, raise_request_exception=True, *, headers=None, query_params=None, **defaults)[source]#
Test utility for testing apps using
django-modern-rest.Based on
django.test.Client. See their docs for advanced usage: https://docs.djangoproject.com/en/dev/topics/testing/tools/This type, in contrast to a regular
Client, setscontent-typeasapplication/json.
- class dmr.test.DMRAsyncClient(enforce_csrf_checks=False, raise_request_exception=True, *, headers=None, query_params=None, **defaults)[source]#
Async version of
DMRClient.Uses
asyncAPI. Requires you toawaitcalls to.get,.post, etc.
Auth#
- dmr.test.disabled_auth(controller_cls: type[Controller[BaseSerializer]], *, request: HttpRequest, user: AbstractBaseUser, auth: SyncAuth | AsyncAuth | None = None) Generator[None][source]#
Temporarily disable all auth for the endpoint for testing.
- Parameters:
controller_cls – Controller whose endpoint is under test.
request – HTTP method of the endpoint to target.
user – User to be used for this request.
auth – Optional auth instance to be used for this request. It is set as
__dmr_auth__attribute, like our regular auth does. Usedmr.security.request_auth()to get it from request.
Added in version 0.13.0.
Throttling#
- dmr.test.reduced_throttling(controller_cls: type[Controller[BaseSerializer]], *, method: HTTPMethod | str, max_requests: int = 2, rate: Rate = Rate.hour, when: Literal['any', 'before_auth', 'after_auth'] = 'any') Generator[SyncThrottle | AsyncThrottle][source]#
Temporarily lower an endpoint’s first throttle so a test can reach it.
Replaces the first throttle of the chosen when with a copy limited to max_requests, so a few real requests trip it instead of the configured rate. Only the endpoint under test is affected; the original throttling is restored on exit. Yields the reduced throttle, whose max_requests tells you how many allowed requests to send before the next one is rejected.
The copy also has its window widened to rate, because lowering just max_requests is not enough for short windows: a
2/secondthrottle would reset between the driven requests and the endpoint would never be rejected. With an hour-long window every request a test sends lands inside the same window.- Parameters:
controller_cls – Controller whose endpoint is under test.
method – HTTP method of the endpoint to target.
max_requests – Limit the throttle is lowered to (
2by default). The window is always widened to one hour, see above.rate – Time window to narrow to (
hourby default).when – When to run the throttle –
'before_auth'(checked before auth, e.g. by IP),'after_auth'(per-user, needs an authenticated request), or'any'(default, the first one checked).
Added in version 0.12.0.
- dmr.test.assert_throttled(response: HttpResponse, *, throttle: SyncThrottle | AsyncThrottle | None = None) None[source]#
Assert that a response was rejected by throttling.
Collapses the repeated
429status, header and error-body checks into a single call:# Just the status + `ratelimit` error: assert_throttled(response) # Also asserts all the headers from the throttle instance exist: assert_throttled(response, throttle=your_throttled_instance)
- Parameters:
response – The response to check.
throttle – Throttle that rejected the request. When given, every header its providers report must be present in the response.
throttle instance defines which headers are reported depends on the header provider’s class:
XRateLimit,RateLimitIETFDraft, or your own provider.Added in version 0.12.0.
- dmr.test.assert_throttling(controller_cls: type[Controller[BaseSerializer]], request_factory: Callable[[], HttpRequest], *, max_requests: int = 2, rate: Rate = Rate.hour, when: Literal['any', 'before_auth', 'after_auth'] = 'any', success_status: HTTPStatus | None = None) tuple[HttpResponse, SyncThrottle][source]#
Reduce the first throttle, drive requests, and assert the
429.Sends max_requests allowed requests, then one that is rejected, and checks it with
assert_throttled()– including every header the reduced throttle reports. Returns the429response, so you can make further assertions on it.Parameters when and rate are passed down to
reduced_throttling()andassert_throttled().Added in version 0.12.0.
- async dmr.test.assert_async_throttling(controller_cls: type[Controller[BaseSerializer]], request_factory: Callable[[], HttpRequest], *, max_requests: int = 2, rate: Rate = Rate.hour, when: Literal['any', 'before_auth', 'after_auth'] = 'any', success_status: HTTPStatus | None = None) tuple[HttpResponse, AsyncThrottle][source]#
Async version of
assert_throttling().Added in version 0.12.0.
Plugins#
Pydantic#
- class dmr.plugins.pydantic.PydanticSerializer[source]#
Serialize and deserialize objects using pydantic.
Pydantic support is optional. To install it run:
pip install 'django-modern-rest[pydantic]'- to_json_kwargs#
Dictionary of kwargs that will be passed to model serialization callbacks.
- Type:
- to_model_kwargs#
Dictionary of kwargs that will be passed to model deserialization callbacks.
- Type:
- classmethod build_context_model(name: str, fields: Mapping[str, ContextField]) ContextModel[source]#
Build the model to parse the whole request context at once.
We build a
typing.TypedDictwhen there are no defaults, because it is the fastest thing thatpydanticcan validate and it does not need any conversion into keyword arguments.When some fields have defaults, we build a regular
dataclasses.dataclass(), sinceTypedDictcannot have them. Defaults are passed as-is, sodataclassesrules apply: mutable defaults like[]or non-frozen models are not allowed.Added in version 0.16.0.
- classmethod deserialize(buffer: bytes | bytearray, *, parser: Parser, request: HttpRequest, model: Any) Any[source]#
Convert string or bytestring to simple python object.
- classmethod from_python(unstructured: Any, model: Any, *, strict: bool | None, extra_namespace: Mapping[str, Any] | None = None) Any[source]#
Parse unstructured data from python primitives into model.
- Parameters:
unstructured – Python objects to be parsed / validated.
model – Python type to serve as a model. Can be any type that
pydanticsupports. Examples:dict[str, int]andBaseModelsubtypes.strict – Whether we use more strict validation rules. For example, it is fine for a request validation to be less strict in some cases and allow type coercition. But, response types need to be strongly validated.
extra_namespace – Optional namespace to rebuild the type adapter. Should be used when there are forward references that pydantic cannot solve by itself.
- Returns:
Structured and validated data.
- Raises:
pydantic_core.ValidationError – When parsing can’t be done.
Changed in version 0.13.0: Added rebuild_namespace parameter was renamed to be extra_namespace.
- optimizer#
alias of
PydanticEndpointOptimizer
- schema_generator#
alias of
PydanticSchemaGenerator
- classmethod serialize(structure: Any, *, renderer: Renderer) bytes[source]#
Convert any object to raw bytestring.
- classmethod serialize_hook(to_serialize: Any) Any[source]#
Customize how some objects are serialized into simple objects.
- classmethod serialize_validation_error(exc: Exception) list[ErrorDetail][source]#
Serialize validation error.
- class dmr.plugins.pydantic.PydanticFastSerializer[source]#
Fast pydantic serializer for cases when you only work with json.
Does not use
parserandrendererpassed objects, does not usedmr.plugins.pyndatic.PydanticSerializer.serialize_hookanddmr.plugins.pyndatic.PydanticSerializer.deserialize_hookmethod.Is built for optimizations only, use with caution.
Only works with
application/jsoncontent type.Added in version 0.6.0: See issue 830.
- classmethod deserialize(buffer: bytes | bytearray, *, parser: Parser, request: HttpRequest, model: Any) Any[source]#
Fast way to serializer pyndatic models into json bytestring.
parser parameter is always ignored.
Changed in version 0.16.0: Now uses faster
json_loadswhen it is available.
- classmethod serialize(structure: Any, *, renderer: Renderer) bytes[source]#
Fast way to serializer pyndatic models into json bytestring.
renderer parameter is always ignored.
- classmethod validate(controller_cls: type[Controller[BaseSerializer]], metadata: EndpointMetadata) None[source]#
Validate that only
jsonparsers and renderers are used.Changed in version 0.16.0: Replaces
is_supportedmethod.
- class dmr.plugins.pydantic.serializer.PydanticEndpointOptimizer[source]#
Optimize endpoints that are parsed with pydantic.
- classmethod optimize_endpoint(metadata: EndpointMetadata) None[source]#
Create models for return types for validation.
- class dmr.plugins.pydantic.schema.PydanticSchemaGenerator[source]#
Generates JSON schema for pydantic objects.
- json_schema_kwargs#
Dictionary of kwargs that will be passed to the
json_schemamethod of pydantic’sTypeAdapter.- Type:
Schemas are registered and cached per annotation, not per serializer.
Changed in version 0.16.0: Added
json_schema_kwargs.
- final class dmr.plugins.pydantic.schema.JsonSchemaKwargs[source]#
Keyword arguments for pydantic’s
json_schemamethod.Added in version 0.16.0.
Msgspec#
- class dmr.plugins.msgspec.MsgspecSerializer[source]#
Serialize and deserialize objects using msgspec.
Msgspec support is optional. To install it run:
pip install 'django-modern-rest[msgspec]'- to_json_kwargs#
Dictionary of kwargs that will be passed to model serialization callbacks.
- Type:
- to_model_kwargs#
Dictionary of kwargs that will be passed to model deserialization callbacks.
- Type:
- classmethod build_context_model(name: str, fields: Mapping[str, ContextField]) ContextModel[source]#
Build the model to parse the whole request context at once.
We always build a
msgspec.Structwithgc=False, it is around x2 faster to validate than atyping.TypedDict. Struct instances are converted into keyword arguments withmsgspec.structs.asdict(). Defaults are passed as-is, somsgspecrules apply: mutable defaults like[1]or non-frozen structs are not allowed.Added in version 0.16.0.
- classmethod deserialize(buffer: bytes | bytearray, *, parser: Parser, request: HttpRequest, model: Any) Any[source]#
Convert string or bytestring to simple python object.
- classmethod from_python(unstructured: Any, model: Any, *, strict: bool | None, extra_namespace: Mapping[str, Any] | None = None) Any[source]#
Parse unstructured data from python primitives into model.
- Parameters:
unstructured – Python objects to be parsed / validated.
model – Python type to serve as a model. Can be any type that
msgspecsupports. Examples:dict[str, int]andBaseModelsubtypes.strict – Whether we use more strict validation rules. For example, it is fine for a request validation to be less strict in some cases and allow type coercition. But, response types need to be strongly validated.
extra_namespace – Not used currently.
- Returns:
Structured and validated data.
- Raises:
msgspec.ValidationError – When parsing can’t be done.
Changed in version 0.13.0: Added extra_namespace parameter.
- optimizer#
alias of
MsgspecEndpointOptimizer
- schema_generator#
alias of
MsgspecSchemaGenerator
- classmethod serialize(structure: Any, *, renderer: Renderer) bytes[source]#
Convert any object to a raw bytestring.
- classmethod serialize_validation_error(exc: Exception) list[ErrorDetail][source]#
Serialize validation error.
- classmethod to_python(structured: Any) Any[source]#
Unparse structured data from a model into Python primitives.
- Parameters:
structured – Model instance.
- Returns:
Unstructured data.
- validation_error#
alias of
ValidationError
- class dmr.plugins.msgspec.serializer.MsgspecEndpointOptimizer[source]#
Optimize endpoints that are parsed with Msgspec.
- classmethod optimize_endpoint(metadata: EndpointMetadata) None[source]#
Does nothing for msgspec.
- final class dmr.plugins.msgspec.schema.JsonSchemaKwargs[source]#
Keyword arguments for msgspec’s
json_schemamethod.Added in version 0.16.0.
- class dmr.plugins.msgspec.schema.MsgspecSchemaGenerator[source]#
Generates JSON schema for msgspec objects.
- json_schema_kwargs#
Dictionary of kwargs that will be passed to the
msgspec.json.schema()function.- Type:
Schemas are registered and cached per annotation, not per serializer.
Changed in version 0.16.0: Added
json_schema_kwargs.
- class dmr.plugins.msgspec.serializer.ToJsonKwargs[source]#
Custom deserializer API options, taken by
msgspec.to_builtins().
- class dmr.plugins.msgspec.serializer.ToModelKwargs[source]#
Custom serializer API options, taken by
msgspec.convert().
- dmr.plugins.msgspec.BodyMsgspec#
Runtime representation of an annotated type.
At its core ‘Annotated[t, dec1, dec2, …]’ is an alias for the type ‘t’ with extra annotations. The alias behaves like a normal typing alias. Instantiating is the same as instantiating the underlying type; binding it to types is also the same.
The metadata itself is stored in a ‘__metadata__’ attribute as a tuple.
alias of
Annotated[_BodyT, <dmr.plugins.msgspec.components.BodyMsgspecComponent object at 0x7fc565336800>]
- class dmr.plugins.msgspec.components.BodyMsgspecComponent[source]#
Bases:
BodyComponentParses body of the request directly into its model with
msgspec.It is
BodyComponentin fast mode, which only works withMsgspecSerializerand parsers that decode into models, likeMsgspecJsonParserandMsgpackParser.Use
BodyMsgspecalias, see Fast body parsing with msgspec.Added in version 0.16.0.
- provide_context_data(endpoint: Endpoint, controller: Controller[BaseSerializer], *, field_model: Any, default: Any = EMPTY) Any[source]#
Return unstructured raw values for
serializer.from_python().It must return the same number of elements that has type vars. Basically, each type var is a model. Each element in a tuple is the corresponding data for that model.
When this method returns not a tuple and there’s only one type variable, it also works.
default is the default value of the endpoint parameter, like
parsed_body: Body[Model | None] = None. When it is notEMPTYand the request has no data for this component, return default as-is.Changed in version 0.16.0: Added default parameter.
- validate(controller_cls: type[Controller[BaseSerializer]], metadata: EndpointMetadata) None[source]#
Validate that the controller uses
msgspecserializer.Other serializers cannot parse bodies directly into their models, so we raise
EndpointMetadataErrorfor them during the import time.
OpenAPI#
Main OpenAPI object:
- class dmr.openapi.openapi.OpenAPI(*, info: Info, openapi: str, self_uri: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$self', alias_priority=2)] = None, json_schema_dialect: str | None = None, servers: list[Server] | None = None, paths: dict[str, PathItem] | None = None, webhooks: dict[str, PathItem | Reference] | None = None, components: Components | None = None, security: list[dict[str, list[str]]] | None = None, tags: list[Tag] | None = None, external_docs: ExternalDocumentation | None = None, x_extensions: dict[str, Any] | None = None)[source]#
This is the root object of the OpenAPI document.
Changed in version 0.13.0: Moved from
dmr.openapi.objects.OpenAPItodmr.openapi.openapi.OpenAPI.Changed in version 0.16.0: Added
self_urifor the$selffield from OpenAPI 3.2. Addedx_extensionsfor specification extensions.- cache_clear() None[source]#
Clear cached schema conversion and validation state.
Use this method after modifying an already converted schema. The next
convert()call rebuilds the schema and validates it unless validation is skipped.Added in version 0.15.0.
- convert(*, skip_validation: bool = False) dict[str, Any][source]#
Convert the object to OpenAPI schema dictionary.
Runs validation if
'django-modern-rest[openapi]'is installed and skip_validation is falsy.The converted dictionary is cached on this instance and reused by subsequent calls. Treat the returned dictionary as read-only and call
cache_clear()after modifying an already converted schema.Skipping validation does not prevent a later call from validating the cached dictionary.
Changed in version 0.15.0: Now we only run schema conversion once per instance and cache the result.
Parts:
- class dmr.openapi.objects.Components(*, schemas: dict[str, Schema] | None = None, responses: dict[str, Response | Reference] | None = None, parameters: dict[str, Parameter | Reference] | None = None, examples: dict[str, Example | Reference] | None = None, request_bodies: dict[str, RequestBody | Reference] | None = None, headers: dict[str, Header | Reference] | None = None, security_schemes: dict[str, SecurityScheme | Reference] | None = None, links: dict[str, Link | Reference] | None = None, callbacks: dict[str, Callback | Reference] | None = None, path_items: dict[str, PathItem] | None = None, media_types: dict[str, MediaType | Reference] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Holds a set of reusable objects for different aspects of the OAS.
All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.
Changed in version 0.16.0: Added
media_typesfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Contact(*, name: str | None = None, url: str | None = None, email: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Contact information for the exposed API.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.Discriminator(*, property_name: str, mapping: dict[str, str] | None = None, default_mapping: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Discriminator Object.
When request bodies or response payloads may be one of a number of different schemas, a discriminator object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the document of an alternative schema based on the value associated with it.
Changed in version 0.16.0: Added
default_mappingfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Encoding(*, content_type: str | None = None, headers: dict[str, Header | Reference] | None = None, style: str | None = None, explode: bool | None = None, allow_reserved: bool | None = None, encoding: dict[str, Encoding] | None = None, item_encoding: Encoding | None = None, prefix_encoding: list[Encoding] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
A single encoding definition applied to a single schema property.
Changed in version 0.16.0: Added
encoding,item_encoding, andprefix_encodingfrom OpenAPI 3.2, they describe nested and sequential encodings. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Example(*, summary: str | None = None, description: str | None = None, value: Any = EMPTY, external_value: str | None = None, data_value: Any = EMPTY, serialized_value: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Example Object.
In all cases, the example value is expected to be compatible with the type schema of its associated value. Tooling implementations MAY choose to validate compatibility automatically, and reject the example value(s) if incompatible.
Changed in version 0.16.0: Added
data_valueandserialized_valuefrom OpenAPI 3.2. They replacevalue, which 3.2 deprecates for non-JSON serialization targets.valueanddata_valuenow default toEMPTYinstead ofNone, becauseNoneis a valid value for them. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.ExternalDocumentation(*, url: str, description: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Allows referencing an external resource for extended documentation.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.Header(*, schema: Schema | None = None, description: str | None = None, required: bool | None = None, deprecated: bool | None = None, style: str | None = None, explode: bool | None = None, example: Any = EMPTY, examples: dict[str, Example | Reference] | None = None, content: dict[str, MediaType | Reference] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Header Object.
The Header Object follows the structure of the Parameter Object with the following changes: All traits that are affected by the location MUST be applicable to a location of header (for example, style).
Changed in version 0.16.0:
contentvalues can now be references.examplenow defaults toEMPTYinstead ofNone, becauseNoneis a valid value for it. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Info(*, title: str, version: str, summary: str | None = None, description: Reference | str | None = None, terms_of_service: str | None = None, contact: Contact | None = None, license: License | None = None, x_extensions: dict[str, Any] | None = None)[source]#
The Info object provides metadata about the API.
The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.License(*, name: str, identifier: str | None = None, url: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
License information for the exposed API.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.Link(*, operation_ref: str | None = None, operation_id: str | None = None, parameters: dict[str, Any] | None = None, request_body: Any = EMPTY, description: str | None = None, server: Server | None = None, x_extensions: dict[str, Any] | None = None)[source]#
The Link object represents a possible design-time link for a response.
The presence of a link does not guarantee the caller’s ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations.
Changed in version 0.16.0:
request_bodynow defaults toEMPTYinstead ofNone, becauseNoneis a valid value for it. Addedx_extensionsfor specification extensions.
- final class dmr.openapi.objects.MediaTypeMetadata(*, example: Any = EMPTY, examples: dict[str, Example | Reference] | None = None, encoding: dict[str, Encoding] | None = None, description: str | None = None, item_encoding: Encoding | None = None, prefix_encoding: list[Encoding] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Media type metadata to be set on a request body.
Changed in version 0.16.0: Added
descriptionfrom OpenAPI 3.2.prefix_encodingis now a list, as the spec requires.examplenow defaults toEMPTYinstead ofNone, becauseNoneis a valid value for it. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.MediaType(*, schema: Schema | None = None, example: Any = EMPTY, examples: dict[str, Example | Reference] | None = None, encoding: dict[str, Encoding] | None = None, description: str | None = None, item_schema: Schema | None = None, item_encoding: Encoding | None = None, prefix_encoding: list[Encoding] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Media Type Object.
Each Media Type Object provides schema and examples for the media type identified by its key.
Changed in version 0.16.0: Added
descriptionfrom OpenAPI 3.2.prefix_encodingis now a list, as the spec requires.examplenow defaults toEMPTYinstead ofNone, becauseNoneis a valid value for it. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.OAuthFlow(*, authorization_url: str | None = None, token_url: str | None = None, refresh_url: str | None = None, scopes: dict[str, str] | None = None, device_authorization_url: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Configuration details for a supported OAuth Flow.
Changed in version 0.16.0: Added
device_authorization_urlfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.OAuthFlows(*, implicit: OAuthFlow | None = None, password: OAuthFlow | None = None, client_credentials: OAuthFlow | None = None, authorization_code: OAuthFlow | None = None, device_authorization: OAuthFlow | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Allows configuration of the supported OAuth Flows.
Changed in version 0.16.0: Added
device_authorizationfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- final class dmr.openapi.objects.OpenAPIFormat(*values)[source]#
OpenAPI format.
See also
Spec: https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#page-13
Formats Registry: https://spec.openapis.org/registry/format/
- class dmr.openapi.objects.Operation(*, tags: list[str] | None = None, summary: str | None = None, description: str | None = None, external_docs: ExternalDocumentation | None = None, operation_id: str | None = None, parameters: list[Parameter | Reference] | None = None, request_body: RequestBody | Reference | None = None, responses: Responses | None = None, callbacks: dict[str, Callback | Reference] | None = None, deprecated: bool | None = None, security: list[SecurityRequirement] | None = None, servers: list[Server] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Describes a single API operation on a path.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.ParameterMetadata(*, description: str | None = None, deprecated: bool | None = None, allow_empty_value: bool | None = None, style: str | None = None, explode: bool | None = None, allow_reserved: bool | None = None, example: Any = EMPTY, examples: dict[str, Example | Reference] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Describes metadata for a single operation parameter.
Changed in version 0.16.0:
examplenow defaults toEMPTYinstead ofNone, becauseNoneis a valid value for it. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Parameter(*, description: str | None = None, deprecated: bool | None = None, allow_empty_value: bool | None = None, style: str | None = None, explode: bool | None = None, allow_reserved: bool | None = None, example: Any = EMPTY, examples: dict[str, Example | Reference] | None = None, x_extensions: dict[str, Any] | None = None, name: str, param_in: Annotated[Literal['query', 'querystring', 'header', 'path', 'cookie'], FieldInfo(annotation=NoneType, required=True, alias='in', alias_priority=2)], schema: Schema | None = None, content: dict[str, MediaType | Reference] | None = None, required: bool | None = None)[source]#
Bases:
ParameterMetadataDescribes a single operation parameter.
Changed in version 0.16.0:
param_inis now typed, it also allows'querystring'from OpenAPI 3.2.contentvalues can now be references.- x_extensions#
Specification extensions, keys must start with
x-.
- dmr.openapi.objects.ParameterLocation#
alias of
Literal[‘query’, ‘querystring’, ‘header’, ‘path’, ‘cookie’]
- class dmr.openapi.objects.PathItem(*, ref: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$ref', alias_priority=2)] = None, summary: str | None = None, description: str | None = None, get: Operation | None = None, put: Operation | None = None, post: Operation | None = None, delete: Operation | None = None, options: Operation | None = None, head: Operation | None = None, patch: Operation | None = None, trace: Operation | None = None, query: Operation | None = None, servers: list[Server] | None = None, parameters: list[Parameter | Reference] | None = None, additional_operations: dict[str, Operation] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Describes the operations available on a single path.
A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.Reference(*, ref: Annotated[str, FieldInfo(annotation=NoneType, required=True, alias='$ref', alias_priority=2)], summary: str | None = None, description: str | None = None)[source]#
A simple object to allow referencing other components in the document.
The $ref string value contains a URI RFC3986, which identifies the location of the value being referenced.
It is not used inside
Schemaobjects: since OpenAPI 3.1,$refin a schema is a JSON Schema keyword, seeSchema.ref.Changed in version 0.16.0: Not allowed in schema positions anymore, use
Schema(ref=...).
- class dmr.openapi.objects.RequestBody(*, content: dict[str, MediaType | Reference], description: str | None = None, required: bool | None = True, x_extensions: dict[str, Any] | None = None)[source]#
Describes a single request body.
Changed in version 0.16.0:
contentvalues can now be references. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Response(*, description: str | None = None, headers: dict[str, Header | Reference] | None = None, content: dict[str, MediaType | Reference] | None = None, links: dict[str, Link | Reference] | None = None, summary: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Describes a single response from an API Operation.
Including design-time, static links to operations based on the response.
Changed in version 0.16.0: Added
summaryfrom OpenAPI 3.2.contentvalues can now be references. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Schema(*, all_of: list[Schema] | None = None, any_of: list[Schema] | None = None, one_of: list[Schema] | None = None, schema_not: Annotated[Schema | None, FieldInfo(annotation=NoneType, required=True, alias='not', alias_priority=2)] = None, schema_if: Annotated[Schema | None, FieldInfo(annotation=NoneType, required=True, alias='if', alias_priority=2)] = None, schema_then: Annotated[Schema | None, FieldInfo(annotation=NoneType, required=True, alias='then', alias_priority=2)] = None, schema_else: Annotated[Schema | None, FieldInfo(annotation=NoneType, required=True, alias='else', alias_priority=2)] = None, dependent_schemas: dict[str, Schema] | None=None, prefix_items: list[Schema] | None = None, items: Schema | bool | None = None, contains: Schema | None = None, properties: dict[str, Schema] | None=None, pattern_properties: dict[str, Schema] | None=None, additional_properties: Schema | bool | None = None, property_names: Schema | None = None, unevaluated_items: Schema | None = None, unevaluated_properties: Schema | None = None, type: OpenAPIType | list[OpenAPIType] | None = None, enum: list[Any] | None = None, const: Any = EMPTY, multiple_of: float | None = None, maximum: float | None = None, exclusive_maximum: float | None = None, minimum: float | None = None, exclusive_minimum: float | None = None, max_length: int | None = None, min_length: int | None = None, pattern: str | None = None, max_items: int | None = None, min_items: int | None = None, unique_items: bool | None = None, max_contains: int | None = None, min_contains: int | None = None, max_properties: int | None = None, min_properties: int | None = None, required: list[str] = <factory>, dependent_required: dict[str, list[str]] | None=None, format: OpenAPIFormat | str | None = None, content_encoding: str | None = None, content_media_type: str | None = None, content_schema: Schema | None = None, title: str | None = None, description: str | None = None, default: Any = EMPTY, deprecated: bool | None = None, read_only: bool | None = None, write_only: bool | None = None, examples: list[Any] | None = None, discriminator: Discriminator | None = None, xml: XML | None = None, external_docs: ExternalDocumentation | None = None, example: Any = EMPTY, dynamic_anchor: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$dynamicAnchor', alias_priority=2)] = None, dynamic_ref: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$dynamicRef', alias_priority=2)] = None, ref: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$ref', alias_priority=2)] = None, anchor: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$anchor', alias_priority=2)] = None, comment: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$comment', alias_priority=2)] = None, schema_uri: Annotated[str | None, FieldInfo(annotation=NoneType, required=True, alias='$schema', alias_priority=2)] = None, defs: Annotated[dict[str, Schema] | None, FieldInfo(annotation=NoneType, required=True, alias='$defs', alias_priority=2)] = None, x_extensions: dict[str, ~typing.Any] | None=None)[source]#
The Schema Object allows the definition of input and output data types.
These types can be objects, but also primitives and arrays. Unless stated otherwise, the property definitions follow those of JSON Schema and do not add any additional semantics. Where JSON Schema indicates that behavior is defined by the application (e.g. for annotations), OAS also defers the definition of semantics to the application consuming the OpenAPI document.
Changed in version 0.16.0:
const,default, andexamplenow default toEMPTYinstead ofNone, becauseNoneis a valid value for them. Subschemas are alwaysSchemaobjects, since OpenAPI 3.1 a$refinside a schema is a JSON Schema keyword (seeref), not aReferenceobject.extensionsis renamed tox_extensions.
- class dmr.openapi.objects.SecurityScheme(*, type: Literal['apiKey', 'http', 'mutualTLS', 'oauth2', 'openIdConnect'], description: str | None = None, name: str | None = None, security_scheme_in: Annotated[Literal['query', 'header', 'cookie'] | None, FieldInfo(annotation=NoneType, required=True, alias='in', alias_priority=2)] = None, scheme: str | None = None, bearer_format: str | None = None, flows: OAuthFlows | None = None, open_id_connect_url: str | None = None, oauth2_metadata_url: str | None = None, deprecated: bool | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Defines a security scheme that can be used by the operations.
Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), mutual TLS (use of a client certificate), OAuth2’s common flows (implicit, password, client credentials and authorization code) as defined in RFC6749, OAuth2’s device authorization flow as defined in RFC8628, and OpenID Connect Discovery. Please note that as of 2020, the implicit flow is about to be deprecated by OAuth 2.0 Security Best Current Practice. Recommended for most use cases is Authorization Code Grant flow with PKCE.
Changed in version 0.16.0: Added
oauth2_metadata_urlanddeprecatedfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.Server(*, url: str, description: str | None = None, variables: dict[str, ServerVariable] | None = None, name: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
An object representing a Server.
Changed in version 0.16.0: Added
namefrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.ServerVariable(*, default: str, enum: list[str] | None = None, description: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
An object representing a Server Variable for server URL template.
Changed in version 0.16.0: Added
x_extensionsfor specification extensions.
- class dmr.openapi.objects.Tag(*, name: str, description: str | None = None, external_docs: ExternalDocumentation | None = None, summary: str | None = None, parent: str | None = None, kind: str | None = None, x_extensions: dict[str, Any] | None = None)[source]#
Adds metadata to a single tag that is used by the Operation object.
It is not mandatory to have a Tag object per tag defined in the Operation object instances.
Changed in version 0.16.0: Added
summary,parent, andkindfrom OpenAPI 3.2. Addedx_extensionsfor specification extensions.
- class dmr.openapi.objects.XML(*, name: str | None = None, namespace: str | None = None, prefix: str | None = None, attribute: bool | None = None, wrapped: bool | None = None, node_type: Literal['element', 'attribute', 'text', 'cdata', 'none'] | None = None, x_extensions: dict[str, Any] | None = None)[source]#
A metadata object that allows for more fine-tuned XML model definitions.
When using arrays, XML element names are not inferred (for singular/plural forms) and the name property SHOULD be used to add that information.
Changed in version 0.16.0: Added
node_typefrom OpenAPI 3.2, it deprecates bothattributeandwrapped. Those two now default toNoneand are only dumped into the schema when they are set explicitly. Addedx_extensionsfor specification extensions.
OpenAPI Core#
- class dmr.openapi.core.merger.ConfigMerger(context: OpenAPIContext)[source]#
Merges OpenAPI configuration with generated paths and components.
This class is responsible for combining the OpenAPI configuration from the context with the generated paths and components to create a complete OpenAPI specification object.
- class dmr.openapi.core.registry.SchemaRegistry[source]#
Registry for
Schemas.Changed in version 0.16.0: Removed
try_unregister: components are now registered only when the final schema references them, seedmr.openapi.generators.SchemaGenerator.register(). References to schemas are nowSchemaobjects with$refset, notReferenceobjects, because OpenAPI 3.1 defines$refas a JSON Schema keyword.- get_reference(schema_name: str | None, annotation: Any | sentinel = EMPTY) Schema | None[source]#
Get a reference to the registered schema, if it exists.
- maybe_resolve_reference(reference: Schema, *, resolution_context: dict[str, Schema] | None = None) Schema[source]#
Resolve a schema with
$refand return the referenced schema back.Schemas without
$refare returned as is. resolution_context holds components that are not registered yet, they are checked before the registered ones.The keywords next to
$ref, likedefault, only annotate that one usage: they are put on top of the component’s own schema, but they never modify the component itself, #1491Changed in version 0.16.0: Falls back to the registered schemas when resolution_context does not have the component. Accepts only
Schemaobjects. Keywords next to$refare kept in the result.
- class dmr.openapi.core.registry.SecuritySchemeRegistry[source]#
Registry for
SecuritySchemes.Changed in version 0.16.0:
schemesis now a property that returns security schemes sorted by name.- register(name: str, scheme: SecurityScheme | Reference) None[source]#
Register security scheme in registry.
- property schemes: dict[str, SecurityScheme | Reference]#
Return security schemes by name.
OpenAPI Generators#
- class dmr.openapi.generators.ComponentParserGenerator(_context: OpenAPIContext)[source]#
Generator for OpenAPI
Parameterobjects.- __call__(operation_id: str, route_metadata: InternalRouteMetadata, metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) tuple[RequestBody | Reference | None, list[Parameter | Reference] | None][source]#
Generate parameters from parsers.
Components with default values are optional: their request bodies are not required and their parameters are not required as well. Except for path parameters, they are always required by OpenAPI.
Changed in version 0.16.0: Now accepts controller_cls parameter instead of serializer. Now accepts route_metadata parameter instead of pattern. Components with default values are now optional.
- final class dmr.openapi.generators.component_parsers.ConverterSchema(model: Any = <class 'str'>, pattern: str | None = None, description: str | None = None)[source]#
Prepared OpenAPI schema of a single Django path converter.
Built-in converters use it to document themselves, and custom ones can provide their own instance through the
__dmr_converter_schema__attribute. Explicit values always override the generated ones.
- class dmr.openapi.generators.ResponseGenerator(_context: OpenAPIContext)[source]#
Generator for OpenAPI
Responseobjects.- __call__(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) dict[str, Response | Reference][source]#
Generate responses from response specs.
Changed in version 0.16.0: Now accepts controller_cls parameter instead of serializer.
- get_schema(response_spec: ResponseSpec, metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], context: OpenAPIContext, *, schema_field_name: Literal['schema', 'item_schema'] = 'schema', used_for_response: bool = True, content_schema: Schema | None = None) Response[source]#
Returns the OpenAPI schema for the response.
Can be customized in
ResponseSpecsubclasses.When content_schema is passed, it is used for all content types instead of the schema generated from the return type.
Changed in version 0.16.0: Added content_schema parameter.
- final class dmr.openapi.generators.schema.LoadedSchema(schema: Schema, defs: dict[str, Schema], annotation: Any, name: str | None)[source]#
Schema of an annotation together with all components it might use.
Nothing from it is registered in the OpenAPI schema yet. Callers transform
schemahowever they need and then pass the final result todmr.openapi.generators.SchemaGenerator.register(), which registers only the components that the result still references.Added in version 0.16.0.
- class dmr.openapi.generators.SchemaGenerator(_context: OpenAPIContext)[source]#
Generate OpenAPI schemas from different type annotations.
Changed in version 0.16.0: Components are not registered while a schema is generated anymore.
load()returns a schema with all its components kept locally,register()registers only the components that are referenced from the final result. Calling the generator does both at once. Removedskip_registrationandregister_referenced_componentsparameters. References to components are returned asSchemaobjects with$refset, not asReferenceobjects.- __call__(annotation: Any, serializer: type[BaseSerializer], *, used_for_response: bool = False) Schema[source]#
Get schema for an annotation and register components it uses.
- Parameters:
annotation – Type annotation to generate the schema for.
serializer – Serializer that knows how to build a raw JSON schema from the annotation.
used_for_response – Whether this schema describes a response, since some serializers generate different schemas for inputs and outputs.
- Raises:
UnsolvableAnnotationsError – when we can’t generate an OpenAPI schema from an existing annotation.
- load(annotation: Any, serializer: type[BaseSerializer], *, used_for_response: bool = False, inline: bool = False) LoadedSchema[source]#
Get schema for an annotation without registering anything.
Here’s the algorithm we use:
First, we try to find an existing reference in the registry
Next, we get a raw JSON schema from the serializer. Models get their own components, so the result is a reference
If nothing worked, we raise an error
- Parameters:
annotation – Type annotation to generate the schema for.
serializer – Serializer that knows how to build a raw JSON schema from the annotation.
used_for_response – Whether this schema describes a response, since some serializers generate different schemas for inputs and outputs.
inline – Resolve
$refin the result: the schema itself and members of its unions are replaced with their definitions. Useful when a schema’s properties are needed.
- Raises:
UnsolvableAnnotationsError – when we can’t generate an OpenAPI schema from an existing annotation.
Added in version 0.16.0.
- register(used: object, *loaded: LoadedSchema) None[source]#
Register components of loaded schemas that are referenced from used.
used is any OpenAPI object built from the loaded schemas, for example, the schema itself, a list of parameters, or a request body. Components that it references directly or through other referenced components are registered, all other components are dropped.
Added in version 0.16.0.
- class dmr.openapi.generators.SecuritySchemeGenerator(_context: OpenAPIContext)[source]#
Generator for OpenAPI Security Schemes.
Responsible for processing authentication providers, extracting their security schemes, registering them in the context, and returning the corresponding security requirements for the operation.
User provided
securityrequirements are merged with the ones generated fromauthbysecurity_merger. Override it in a subclass and set the subclass asdmr.openapi.OpenAPIContext.security_scheme_clsto change how they are merged.Changed in version 0.16.0: Added
security_mergerandsecuritysupport.- __call__(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) list[SecurityRequirement] | None[source]#
Process auth providers and generate security requirements.
Iterates over the provided authentication providers, registers their security schemes in the global registry, and collects their security usage requirements. Semantic schema providers can then inject their own requirements into the collected ones.
User provided
securityfrom metadata is merged last withsecurity_merger. Its security schemes are never registered, they must be declared incomponentsofOpenAPIConfig.When there are no requirements but the document defines global
security, returns an explicit[]so the operation opts out of the global requirements instead of inheriting them.Changed in version 0.16.0: Now accepts metadata and controller_cls parameters. User provided
securityrequirements are merged as well.
- security_merger: ClassVar[SecurityRequirementMerger] = <dmr.semantic_schema.OrSecurityRequirementMerger object>#
Merges user provided
securitywith requirements fromauth. By default, they are joined as alternatives withORlogic.
- class dmr.openapi.generators.OperationIdGenerator(_context: OpenAPIContext)[source]#
Generator for unique OpenAPI operation IDs.
The Operation ID builder is responsible for creating unique operation IDs for OpenAPI operations. It uses the explicit
operation_idfrom endpoint metadata if available, otherwise generates one from the HTTP method and path followingRFC 3986specifications. All generated operation IDs are registered in the registry to ensure uniqueness across the OpenAPI specification.- __call__(path: str, metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) str[source]#
Generate a unique operation ID for an OpenAPI operation.
Uses the explicit
operation_idfrom endpoint metadata if available, otherwise generates one from the HTTP method and path. The operation ID is registered in the registry to ensure uniqueness.Changed in version 0.16.0: Now accepts controller_cls parameter instead of suffix and serializer.
- generate_suffix(path: str, metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]]) str[source]#
Generate suffix for operation ID.
Added in version 0.16.0.
- class dmr.openapi.generators.ParameterGenerator(_context: OpenAPIContext)[source]#
Generator for OpenAPI
Parameterobjects.- __call__(model: Any, model_meta: tuple[Any, ...], metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], *, param_in: Literal['query', 'querystring', 'header', 'path', 'cookie']) list[Parameter | Reference][source]#
Generate parameter spec for the OpenAPI.
Parameters are generated from the properties of object schemas. Unions like
Query[Model | None] = NoneorQuery[Model | Literal['']] = ''are supported: only their object members have properties, other members can only come from defaults, not from the request. When there are several object members, a parameter is required only when it is required by all of them.Changed in version 0.16.0: Now accepts metadata and controller_cls parameters. Removed serializer and context parameters. Union models are now supported.
Collectors#
- final class dmr.openapi.collector.InternalRouteMetadata(path: str, is_regex: bool)[source]#
Represents the metadata we need to create OpenAPI path parameters.
Used for regular DMR views and URLs. It is not used for routing and is only needed for metadata.
Added in version 0.16.0.
- final class dmr.openapi.collector.ExternalRouteMetadata(path: str, is_regex: bool, openapi: PathItem | None)[source]#
Represents the metadata we need to reuse external OpenAPI parameters.
Used for external views and URLs. It is not used for routing and is only needed for metadata.
Added in version 0.16.0.
Existing OpenAPI views#
Existing implementations:
- class dmr.openapi.views.ScalarView(**kwargs)[source]#
View for rendering the OpenAPI schema with Scalar.
Renders an interactive HTML page that allows exploring the
OpenAPIspecification using Scalar API Reference.- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema using Scalar template.
- class dmr.openapi.views.SwaggerView(**kwargs)[source]#
View for rendering the OpenAPI schema with Swagger UI.
Renders an interactive HTML page that allows exploring the
OpenAPIspecification using Swagger UI components.- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema using Swagger template.
- class dmr.openapi.views.RedocView(**kwargs)[source]#
View for rendering the OpenAPI schema with Redoc.
Renders an interactive HTML page that allows exploring the
OpenAPIspecification using Redoc components.- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema using Redoc template.
- class dmr.openapi.views.StoplightView(**kwargs)[source]#
View for rendering the OpenAPI schema with Stoplight.
Renders an interactive HTML page that allows exploring the
OpenAPIspecification using Stoplight API Reference.- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema using Stoplight template.
- class dmr.openapi.views.OpenAPIJsonView(**kwargs)[source]#
View for returning the OpenAPI schema as JSON.
Produces a JSON representation of the
OpenAPIspecification that can be used by API documentation tools and client code generators.- content_type#
Content type of the rendered response. Defaults to
"application/json".- Type:
ClassVar[str]
- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema as JSON response.
- class dmr.openapi.views.yaml.OpenAPIYamlView(**kwargs)[source]#
View for returning the OpenAPI schema as YAML.
This view mirrors
OpenAPIJsonView, but renders the converted schema usingpyyaml. Produces a YAML representation of theOpenAPIspecification that can be used by API documentation tools and client code generators.- get(request: HttpRequest) HttpResponse[source]#
Render the OpenAPI schema as YAML response.
Base classes:
- class dmr.openapi.views.base.OpenAPIView(**kwargs)[source]#
Base view for serving an OpenAPI schema.
This view extends Django’s
Viewto accept anOpenAPIinstance viaas_view(). The passed schema is stored on the view class and can be rendered in any concrete subclass (for example, as JSON or YAML).- classmethod as_view(schema: OpenAPI, *, skip_validation: bool = False, **initkwargs: Any) Callable[[...], HttpResponseBase][source]#
Create a view function bound to the given OpenAPI schema.