.. |br| raw:: html

**********************
Functional overview
**********************

------------------------------
OpenAPI specification overview
------------------------------

This library generates OpenAPI 2.0 documents. The authoritative specification for this document's structure will always
be the official documentation over at `swagger.io <https://swagger.io/>`__ and the `OpenAPI 2.0 specification
page <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md>`__.

Because the above specifications are a bit heavy and convoluted, here is a general overview of how the specification
is structured, starting from the root ``Swagger`` object.

* :class:`.Swagger` object
   + ``info``, ``schemes``, ``securityDefinitions`` and other informative attributes
   + ``paths``: :class:`.Paths` object
      A list of all the paths in the API in the form of a mapping

      - ``{path}``: :class:`.PathItem` - each :class:`.PathItem` has multiple operations keyed by method
         * ``{http_method}``: :class:`.Operation`
            Each operation is thus uniquely identified by its ``(path, http_method)`` combination,
            e.g. ``GET /articles/``, ``POST /articles/``, etc.
         * ``parameters``: [:class:`.Parameter`] - and a list of path parameters
   + ``definitions``: named Models
      A list of all the named models in the API in the form of a mapping

      - ``{ModelName}``: :class:`.Schema`

* :class:`.Operation` contains the following information about each operation:
   + ``parameters``: [:class:`.Parameter`]
      A list of all the *query*, *header* and *form* parameters accepted by the operation.

      - there can also be **at most one** body parameter whose structure is represented by a
        :class:`.Schema` or a reference to one (:class:`.SchemaRef`)
   + ``responses``: :class:`.Responses`
      A list of all the possible responses the operation is expected to return. Each response can optionally have a
      :class:`.Schema` which describes the structure of its body.

      - ``{status_code}``: :class:`.Response` - mapping of status code to response definition

   + ``operationId`` - should be unique across all operations
   + ``tags`` - used to group operations in the listing

It is interesting to note the main differences between :class:`.Parameter` and :class:`.Schema` objects:

+----------------------------------------------------------+-----------------------------------------------------------+
| :class:`.Schema`                                         | :class:`.Parameter`                                       |
+==========================================================+===========================================================+
| Can nest other Schemas                                   | Cannot nest other Parameters |br|                         |
|                                                          | Can only nest a Schema if the parameter is ``in: body``   |
+----------------------------------------------------------+-----------------------------------------------------------+
| Cannot describe file uploads |br|                        | Can describe file uploads via ``type`` = ``file``, |br|   |
| - ``file`` is not permitted as a value for ``type``      | but only as part of a form :class:`.Operation` [#formop]_ |
+----------------------------------------------------------+-----------------------------------------------------------+
| Can be used in :class:`.Response`\ s                     | Cannot be used in :class:`.Response`\ s                   |
+----------------------------------------------------------+-----------------------------------------------------------+
| Cannot be used in form :class:`.Operation`\ s [#formop]_ | Can be used in form :class:`.Operation`\ s [#formop]_     |
+----------------------------------------------------------+-----------------------------------------------------------+
| Can only describe request or response bodies             | Can describe ``query``, ``form``, ``header`` or ``path``  |
|                                                          | parameters                                                |
+----------------------------------------------------------+-----------------------------------------------------------+

.. [#formop] a form Operation is an :class:`.Operation` that consumes ``multipart/form-data`` or
   ``application/x-www-form-urlencoded`` content

      * a form Operation cannot have ``body`` parameters
      * a non-form operation cannot have ``form`` parameters

----------------
Default behavior
----------------

This section describes where information is sourced from when using the default generation process.

* :class:`.Paths` are generated by exploring the patterns registered in your default ``urlconf``, or the ``patterns``
  and ``urlconf`` you specified when constructing :class:`.OpenAPISchemaGenerator`; only views inheriting from Django
  Rest Framework's ``APIView`` are looked at, all other views are ignored
* ``path`` :class:`.Parameter`\ s are generated by looking in the URL pattern for any template parameters; attempts are
  made to guess their type from the views ``queryset`` and ``lookup_field``, if applicable. You can override path
  parameters via ``manual_parameters`` in :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`.
* ``query`` :class:`.Parameter`\ s - i.e. parameters specified in the URL as ``/path/?query1=value&query2=value`` -
  are generated from your view's ``filter_backends`` and ``paginator``, if any are declared. Additional parameters can
  be specified via the ``query_serializer`` and ``manual_parameters`` arguments of
  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`
* The request body is only generated for the HTTP ``POST``, ``PUT`` and ``PATCH`` methods, and is sourced from the
  view's ``serializer_class``. You can also override the request body using the ``request_body`` argument of
  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`.

   - if the view represents a form request (that is, all its parsers are of the ``multipart/form-data`` or
     ``application/x-www-form-urlencoded`` media types), the request body will be output as ``form``
     :class:`.Parameter`\ s
   - if it is not a form request, the request body will be output as a single ``body`` :class:`.Parameter` wrapped
     around a :class:`.Schema`

* ``header`` :class:`.Parameter`\ s are supported by the OpenAPI specification but are never generated by this library;
  you can still add them using ``manual_parameters``.
* :class:`.Responses` are generated as follows:

   + if ``responses`` is provided to :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>` and contains at least
     one success status code (i.e. any `2xx` status code), no automatic response is generated and the given response
     is used as described in the :func:`@swagger_auto_schema documentation <.swagger_auto_schema>`
   + otherwise, an attempt is made to generate a default response:

      - the success status code is assumed to be ``204`` for ``DELETE`` requests, ``201`` for ``POST`` requests, and
        ``200`` for all other request methods
      - if the view has a request body, the same ``Serializer`` or :class:`.Schema` as in the request body is used
        in generating the :class:`.Response` schema; this is inline with the default ``GenericAPIView`` and
        ``GenericViewSet`` behavior
      - if the view has no request body, its ``serializer_class`` is used to generate the :class:`.Response` schema
      - if the view is a list view (as defined by :func:`.is_list_view`), the response schema is wrapped in an array
      - if the view is also paginated, the response schema is then wrapped in the appropriate paging response structure
      - the description of the response is left blank

* :class:`.Response` headers are supported by the OpenAPI specification but not currently supported by this library;
  you can still add them manually by providing an `appropriately structured dictionary
  <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#headersObject>`_
  to the ``headers`` property of a :class:`.Response` object
* *descriptions* for :class:`.Operation`\ s, :class:`.Parameter`\ s and :class:`.Schema`\ s are picked up from
  docstrings and ``help_text`` attributes in the same manner as the `default DRF SchemaGenerator
  <http://www.django-rest-framework.org/api-guide/schemas/#schemas-as-documentation>`_
* .. _custom-spec-base-url:

  The base URL for the API consists of three values - the ``host``, ``schemes`` and ``basePath`` attributes
* The host name and scheme are determined, in descending order of priority:

   + from the ``url`` argument passed to :func:`.get_schema_view` (more specifically, to the underlying
     :class:`.OpenAPISchemaGenerator`)
   + from the :ref:`DEFAULT_API_URL setting <default-swagger-settings>`
   + inferred from the request made to the schema endpoint

   For example, an url of ``https://www.example.com:8080/some/path`` will populate the ``host`` and ``schemes``
   attributes with ``www.example.com:8080`` and ``['https']``, respectively. The path component will be ignored.
* The base path is determined as the concatenation of two variables:

   #. the `SCRIPT_NAME`_ wsgi environment variable; this is set, for example, when serving the site from a
      sub-path using web server url rewriting

      .. Tip::

         The Django `FORCE_SCRIPT_NAME`_ setting can be used to override the `SCRIPT_NAME`_ or set it when it's
         missing from the environment.

   #. the longest common path prefix of all the urls in your API - see :meth:`.determine_path_prefix`

* When using API versioning with ``NamespaceVersioning`` or ``URLPathVersioning``, versioned endpoints that do not
  match the version used to access the ``SchemaView`` will be excluded from the endpoint list - for example,
  ``/api/v1.0/endpoint`` will be shown when viewing ``/api/v1.0/swagger/``, while ``/api/v2.0/endpoint`` will not

  Other versioning schemes are not presently supported.

---------------------
A note on limitations
---------------------

When schema generation is requested, available endpoints are inspected by enumeration all the routes registered in
Django's urlconf. Each registered view is then artificially instantiated for introspection, and it is this step that
brings some limitations to what can be done:

* the ``request`` the view sees will always be the request made against the schema view endpoint
  - e.g. ``GET /swagger.yaml``
* path parameters will not be filled

This means that you could get surprizing results if your ``get_serializer`` or ``get_serializer_class`` methods
depend on the incoming request, call ``get_object`` or in general depend on any stateful logic. You can prevent this
in a few ways:

* provide a fixed serializer for request and response body introspection using
  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`, to prevent ``get_serializer`` from being called on
  the view
* :ref:`exclude your endpoint from introspection <custom-spec-excluding-endpoints>`
* use the ``swagger_fake_view`` marker to detect requests generated by ``drf-yasg``:

   .. code-block:: python

     def get_serializer_class(self):
        if getattr(self, 'swagger_fake_view', False):
           return TodoTreeSerializer

        raise NotImplementedError("must not call this")

.. _SCRIPT_NAME: https://www.python.org/dev/peps/pep-0333/#environ-variables
.. _FORCE_SCRIPT_NAME: https://docs.djangoproject.com/en/2.0/ref/settings/#force-script-name
