Using controller ================ Creating endpoints ------------------ Controllers consist of :class:`~dmr.endpoint.Endpoint` objects. Each HTTP method is an independent endpoint. The simplest way to create an endpoint is to define sync or async method with the right name (any HTTP method verb): .. literalinclude:: /examples/using_controller/first_example.py :caption: views.py :language: python :linenos: There will be several things that ``django-modern-rest`` will do for you here: 1. It will know that ``post`` endpoint will handle ``POST`` HTTP method, it is true for all HTTP methods, except :ref:`OPTIONS ` (click to know why) 2. It will know that ``post`` will return :class:`str` as a response type spec. There's **no** implicit type conversions in ``django-modern-rest``. If your endpoint declares something to be returned, it must return this type 3. It will infer the default status code for ``post``, which will be ``201``. All other endpoints would have ``200`` as the default 4. All this metadata will be used to validate responses from this endpoint. Returning ``[]`` from ``post`` would trigger :exc:`~dmr.exceptions.ResponseSchemaError`, unless :ref:`response_validation` is explicitly turned off 5. The same metadata will be used to render OpenAPI spec ``django-modern-rest`` never creates implicit methods for you. No ``HEAD``, no :ref:`OPTIONS `, if you need them – create them explicitly. Returning responses ------------------- We have two general modes of working with responses: 1. Returning just raw data from "raw endpoints" 2. Returning real :class:`~django.http.HttpResponse` instances with granular configuration from "real endpoints" Raw endpoints ------------- .. note:: "Raw endpoints" always have a response spec generated by default. Prefer :func:`~dmr.endpoint.modify` in simpler cases. "Raw endpoints" can be either undecorated or can use :func:`~dmr.endpoint.modify` decorator to modify the response spec that will be **generated by default**. .. literalinclude:: /examples/using_controller/modify.py :caption: views.py :language: python :linenos: :emphasize-lines: 14 Other response specs can be specified via ``extra_responses`` param to :func:`~dmr.endpoint.modify`, :attr:`~dmr.controller.Controller.responses` ``Controller`` attribute, or :attr:`~dmr.settings.Settings.responses` global setting. Make sure that all responses that can be returned are described! .. important:: Despite the fact, that ``django-modern-rest`` does not have its own request and response primitives and uses :class:`~django.http.HttpRequest` and :class:`~django.http.HttpResponse`, users must not return Django responses directly. Instead, use any of the public APIs: - :meth:`~dmr.controller.Controller.to_response` - :meth:`~dmr.controller.Controller.to_error` - :exc:`~dmr.response.APIError` In case when you don't have a controller / endpoint instance (like in a middleware, for example), you can fallback to using :func:`~dmr.response.build_response` lower level primitive. Why? 1. You can mess up the default headers / status codes 2. You won't have the right json serializer / deserializer, which can be both slow and error-prone Real endpoints -------------- .. note:: No response spec is generated by default for "real endpoints". All response specs must be provided manually. But, this way is way more configurable. "Real endpoints" can use :func:`~dmr.endpoint.validate` decorator, :attr:`~dmr.controller.Controller.responses` ``Controller`` attribute, or :attr:`~dmr.settings.Settings.responses` global setting to specify all possible responses. To do that we utilize :class:`~dmr.metadata.ResponseSpec`: .. literalinclude:: /examples/using_controller/validate.py :caption: views.py :language: python :linenos: :emphasize-lines: 15-20 ``@validate`` decorator is useful but is not required for real endpoint's declaration. Instead, you can specify response specs in ``response`` field of controller / settings. .. literalinclude:: /examples/using_controller/implicit_validate.py :caption: views.py :language: python :linenos: :emphasize-lines: 15-18 If :ref:`response validation ` passes, then it is all fine! .. important:: At least one explicit response spec is required for ``@validate`` endpoints. Note that semantic responses from auth / components / etc are not counted when validating real endpoints. You still have to use at least one explicit specification declaration. Request lifecycle ----------------- Here's the top level view on how request / response lifecycle looks like: .. mermaid:: :caption: Request lifecycle :config: {"theme": "forest"} graph Start[New request] --> BeforeThrottle[Throttling based on IP if any or 429]; BeforeThrottle --> RendererNegotiation[Renderer is negotiated or 406]; RendererNegotiation --> Auth[Auth if any or 401]; Auth --> AfterThrottle[Throttling based on auth if any or 429]; AfterThrottle --> ParserNegotiation[Parser is negotiated if any or 400]; ParserNegotiation --> DataValidation[Request data is validated if any or 400]; DataValidation --> BusinessLogic[Business logic]; BusinessLogic --> Renderer[Response rendering]; Renderer --> ResponseValidation[Response validation if any or 419]; Customizing controllers ----------------------- .. tip:: This is a sneak peek into our advanced API. 90% of users will never need this. ``Controller`` is built to be customized with a class-level API. If you need granular control, you can change anything. - :attr:`~dmr.controller.Controller.allowed_http_methods` to support custom HTTP methods like ``QUERY`` or your custom DSLs on top of HTTP - :attr:`~dmr.controller.Controller.endpoint_cls` to customize how endpoints are created - :attr:`~dmr.controller.Controller.csrf_exempt` to customize whether or not this controller is exempted from the CSRF - :attr:`~dmr.controller.Controller.controller_validator_cls` to customize how controller is validated in import time You can also customize :class:`~dmr.endpoint.Endpoint` to change how API methods are executed: - :attr:`~dmr.endpoint.Endpoint.serializer_context_cls` to customize how model for serialization of incoming data is created Check out our :doc:`Public API <../deep-dive/public-api>` for the most advanced features. What's next? ------------ .. grid:: 3 3 2 2 :class-row: surface :padding: 0 :gutter: 2 .. grid-item-card:: Headers and cookies :link: headers-and-cookies :link-type: doc Learn how to describe response headers and cookies. .. grid-item-card:: Redirects :link: redirects :link-type: doc Learn how to return HTTP redirect responses. .. grid-item-card:: Files :link: files :link-type: doc Learn how to return file responses. .. grid-item-card:: Validation :link: validation :link-type: doc Learn about optional response validation. .. toctree:: :hidden: validation.rst headers-and-cookies.rst redirects.rst files.rst meta.rst