1.. |br| raw:: html
2
3   <br />
4
5**********************
6Functional overview
7**********************
8
9------------------------------
10OpenAPI specification overview
11------------------------------
12
13This library generates OpenAPI 2.0 documents. The authoritative specification for this document's structure will always
14be the official documentation over at `swagger.io <https://swagger.io/>`__ and the `OpenAPI 2.0 specification
15page <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md>`__.
16
17Because the above specifications are a bit heavy and convoluted, here is a general overview of how the specification
18is structured, starting from the root ``Swagger`` object.
19
20* :class:`.Swagger` object
21   + ``info``, ``schemes``, ``securityDefinitions`` and other informative attributes
22   + ``paths``: :class:`.Paths` object
23      A list of all the paths in the API in the form of a mapping
24
25      - ``{path}``: :class:`.PathItem` - each :class:`.PathItem` has multiple operations keyed by method
26         * ``{http_method}``: :class:`.Operation`
27            Each operation is thus uniquely identified by its ``(path, http_method)`` combination,
28            e.g. ``GET /articles/``, ``POST /articles/``, etc.
29         * ``parameters``: [:class:`.Parameter`] - and a list of path parameters
30   + ``definitions``: named Models
31      A list of all the named models in the API in the form of a mapping
32
33      - ``{ModelName}``: :class:`.Schema`
34
35* :class:`.Operation` contains the following information about each operation:
36   + ``parameters``: [:class:`.Parameter`]
37      A list of all the *query*, *header* and *form* parameters accepted by the operation.
38
39      - there can also be **at most one** body parameter whose structure is represented by a
40        :class:`.Schema` or a reference to one (:class:`.SchemaRef`)
41   + ``responses``: :class:`.Responses`
42      A list of all the possible responses the operation is expected to return. Each response can optionally have a
43      :class:`.Schema` which describes the structure of its body.
44
45      - ``{status_code}``: :class:`.Response` - mapping of status code to response definition
46
47   + ``operationId`` - should be unique across all operations
48   + ``tags`` - used to group operations in the listing
49
50It is interesting to note the main differences between :class:`.Parameter` and :class:`.Schema` objects:
51
52+----------------------------------------------------------+-----------------------------------------------------------+
53| :class:`.Schema`                                         | :class:`.Parameter`                                       |
54+==========================================================+===========================================================+
55| Can nest other Schemas                                   | Cannot nest other Parameters |br|                         |
56|                                                          | Can only nest a Schema if the parameter is ``in: body``   |
57+----------------------------------------------------------+-----------------------------------------------------------+
58| Cannot describe file uploads |br|                        | Can describe file uploads via ``type`` = ``file``, |br|   |
59| - ``file`` is not permitted as a value for ``type``      | but only as part of a form :class:`.Operation` [#formop]_ |
60+----------------------------------------------------------+-----------------------------------------------------------+
61| Can be used in :class:`.Response`\ s                     | Cannot be used in :class:`.Response`\ s                   |
62+----------------------------------------------------------+-----------------------------------------------------------+
63| Cannot be used in form :class:`.Operation`\ s [#formop]_ | Can be used in form :class:`.Operation`\ s [#formop]_     |
64+----------------------------------------------------------+-----------------------------------------------------------+
65| Can only describe request or response bodies             | Can describe ``query``, ``form``, ``header`` or ``path``  |
66|                                                          | parameters                                                |
67+----------------------------------------------------------+-----------------------------------------------------------+
68
69.. [#formop] a form Operation is an :class:`.Operation` that consumes ``multipart/form-data`` or
70   ``application/x-www-form-urlencoded`` content
71
72      * a form Operation cannot have ``body`` parameters
73      * a non-form operation cannot have ``form`` parameters
74
75----------------
76Default behavior
77----------------
78
79This section describes where information is sourced from when using the default generation process.
80
81* :class:`.Paths` are generated by exploring the patterns registered in your default ``urlconf``, or the ``patterns``
82  and ``urlconf`` you specified when constructing :class:`.OpenAPISchemaGenerator`; only views inheriting from Django
83  Rest Framework's ``APIView`` are looked at, all other views are ignored
84* ``path`` :class:`.Parameter`\ s are generated by looking in the URL pattern for any template parameters; attempts are
85  made to guess their type from the views ``queryset`` and ``lookup_field``, if applicable. You can override path
86  parameters via ``manual_parameters`` in :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`.
87* ``query`` :class:`.Parameter`\ s - i.e. parameters specified in the URL as ``/path/?query1=value&query2=value`` -
88  are generated from your view's ``filter_backends`` and ``paginator``, if any are declared. Additional parameters can
89  be specified via the ``query_serializer`` and ``manual_parameters`` arguments of
90  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`
91* The request body is only generated for the HTTP ``POST``, ``PUT`` and ``PATCH`` methods, and is sourced from the
92  view's ``serializer_class``. You can also override the request body using the ``request_body`` argument of
93  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`.
94
95   - if the view represents a form request (that is, all its parsers are of the ``multipart/form-data`` or
96     ``application/x-www-form-urlencoded`` media types), the request body will be output as ``form``
97     :class:`.Parameter`\ s
98   - if it is not a form request, the request body will be output as a single ``body`` :class:`.Parameter` wrapped
99     around a :class:`.Schema`
100
101* ``header`` :class:`.Parameter`\ s are supported by the OpenAPI specification but are never generated by this library;
102  you can still add them using ``manual_parameters``.
103* :class:`.Responses` are generated as follows:
104
105   + if ``responses`` is provided to :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>` and contains at least
106     one success status code (i.e. any `2xx` status code), no automatic response is generated and the given response
107     is used as described in the :func:`@swagger_auto_schema documentation <.swagger_auto_schema>`
108   + otherwise, an attempt is made to generate a default response:
109
110      - the success status code is assumed to be ``204`` for ``DELETE`` requests, ``201`` for ``POST`` requests, and
111        ``200`` for all other request methods
112      - if the view has a request body, the same ``Serializer`` or :class:`.Schema` as in the request body is used
113        in generating the :class:`.Response` schema; this is inline with the default ``GenericAPIView`` and
114        ``GenericViewSet`` behavior
115      - if the view has no request body, its ``serializer_class`` is used to generate the :class:`.Response` schema
116      - if the view is a list view (as defined by :func:`.is_list_view`), the response schema is wrapped in an array
117      - if the view is also paginated, the response schema is then wrapped in the appropriate paging response structure
118      - the description of the response is left blank
119
120* :class:`.Response` headers are supported by the OpenAPI specification but not currently supported by this library;
121  you can still add them manually by providing an `appropriately structured dictionary
122  <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#headersObject>`_
123  to the ``headers`` property of a :class:`.Response` object
124* *descriptions* for :class:`.Operation`\ s, :class:`.Parameter`\ s and :class:`.Schema`\ s are picked up from
125  docstrings and ``help_text`` attributes in the same manner as the `default DRF SchemaGenerator
126  <http://www.django-rest-framework.org/api-guide/schemas/#schemas-as-documentation>`_
127* .. _custom-spec-base-url:
128
129  The base URL for the API consists of three values - the ``host``, ``schemes`` and ``basePath`` attributes
130* The host name and scheme are determined, in descending order of priority:
131
132   + from the ``url`` argument passed to :func:`.get_schema_view` (more specifically, to the underlying
133     :class:`.OpenAPISchemaGenerator`)
134   + from the :ref:`DEFAULT_API_URL setting <default-swagger-settings>`
135   + inferred from the request made to the schema endpoint
136
137   For example, an url of ``https://www.example.com:8080/some/path`` will populate the ``host`` and ``schemes``
138   attributes with ``www.example.com:8080`` and ``['https']``, respectively. The path component will be ignored.
139* The base path is determined as the concatenation of two variables:
140
141   #. the `SCRIPT_NAME`_ wsgi environment variable; this is set, for example, when serving the site from a
142      sub-path using web server url rewriting
143
144      .. Tip::
145
146         The Django `FORCE_SCRIPT_NAME`_ setting can be used to override the `SCRIPT_NAME`_ or set it when it's
147         missing from the environment.
148
149   #. the longest common path prefix of all the urls in your API - see :meth:`.determine_path_prefix`
150
151* When using API versioning with ``NamespaceVersioning`` or ``URLPathVersioning``, versioned endpoints that do not
152  match the version used to access the ``SchemaView`` will be excluded from the endpoint list - for example,
153  ``/api/v1.0/endpoint`` will be shown when viewing ``/api/v1.0/swagger/``, while ``/api/v2.0/endpoint`` will not
154
155  Other versioning schemes are not presently supported.
156
157---------------------
158A note on limitations
159---------------------
160
161When schema generation is requested, available endpoints are inspected by enumeration all the routes registered in
162Django's urlconf. Each registered view is then artificially instantiated for introspection, and it is this step that
163brings some limitations to what can be done:
164
165* the ``request`` the view sees will always be the request made against the schema view endpoint
166  - e.g. ``GET /swagger.yaml``
167* path parameters will not be filled
168
169This means that you could get surprizing results if your ``get_serializer`` or ``get_serializer_class`` methods
170depend on the incoming request, call ``get_object`` or in general depend on any stateful logic. You can prevent this
171in a few ways:
172
173* provide a fixed serializer for request and response body introspection using
174  :ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`, to prevent ``get_serializer`` from being called on
175  the view
176* :ref:`exclude your endpoint from introspection <custom-spec-excluding-endpoints>`
177* use the ``swagger_fake_view`` marker to detect requests generated by ``drf-yasg``:
178
179   .. code-block:: python
180
181     def get_serializer_class(self):
182        if getattr(self, 'swagger_fake_view', False):
183           return TodoTreeSerializer
184
185        raise NotImplementedError("must not call this")
186
187.. _SCRIPT_NAME: https://www.python.org/dev/peps/pep-0333/#environ-variables
188.. _FORCE_SCRIPT_NAME: https://docs.djangoproject.com/en/2.0/ref/settings/#force-script-name
189