Components¶
django-modern-rest utilizes component approach to parse all
the unstructured things like headers, body, and cookies
into a strongly typed and validated model.
To use a component, you can just add it as a parameter
to your endpoint method inside a Controller.
How does it work?
In import time, when controller is first created, we iterate over all existing endpoints in this class
For each endpoint we fetch method annotations and find all
ComponentParserobjects, they will be treated as component parsersNext, we create a request parsing model during the import time, with all combined fields to be parsed later
In runtime, when request is received, we provide the needed data for this single parsing model
If everything is ok, we call the needed endpoint with the correct data
If there’s a parsing error we raise
RequestSerializationErrorand return a beautiful error message for the user
You can use existing ones or create your own.
Note
All existing components should only be inherited for parsing. If you want to change the implementation details of a component – create a new one from scratch.
You can still delegate parts of the work to existing ones.
What is inside a component?¶
All components consist of two parts:
The first one is a
ComponentParsersubclass, which knows how to provide the required data for itself, build OpenAPI schemas and etc. For example:QueryComponentThe second part is a
typing.Annotatedbased annotation that has a component parser instance as metadata. These annotations will be used by the end users. For example,Query
Browse components¶
Parsing query parameters.
Parsing header parameters.
Parsing cookie parameters.
Parsing path parameters.
Parsing request body.
Uploading files.
API Reference¶
- class dmr.components.ComponentParser[source]¶
Base abstract provider for request components.
- conditional_types(model: Any, model_meta: tuple[Any, ...]) Mapping[str, Any][source]¶
Provide conditional parsing types based on content type.
Some components parser might define different input models based on the request’s content type.
This method must return a mapping of content_type to the model. If this component support this.
- context_name: ClassVar[str]¶
All subtypes must provide a unique name that will be used to parse context.
We use a single context for all parsing, this component will live under a dict field with this name.
- abstractmethod get_schema(model: Any, model_meta: tuple[Any, ...], metadata: EndpointMetadata, serializer: type[BaseSerializer], context: OpenAPIContext) list[Parameter | Reference] | RequestBody[source]¶
Generate OpenAPI spec for component.
- abstractmethod provide_context_data(endpoint: Endpoint, controller: Controller[BaseSerializer], *, field_model: Any) Any | tuple[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.
- provide_response_specs(metadata: EndpointMetadata, controller_cls: type[Controller[BaseSerializer]], existing_responses: Mapping[HTTPStatus, ResponseSpec]) list[ResponseSpec][source]¶
Return a list of extra responses that this component produces.
For example, when parsing something, we always have an option to fail a parsing, if some request does not fit our model.
- validate(controller_cls: type[Controller[BaseSerializer]], metadata: EndpointMetadata) None[source]¶
Validates that the component is correctly defined.
By default does nothing. Runs in import time.