Add security requirements handling (#54)

* Add security requirements handling
* Update swagger-ui to 3.9.2, ReDoc to 1.20.0

Closes #39.
openapi3
Cristi Vîjdea 2018-01-23 12:43:25 +02:00 committed by GitHub
parent f18ff60ae7
commit fc35d9043e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 340 additions and 293 deletions

View File

@ -185,71 +185,8 @@ c. ``SWAGGER_SETTINGS`` and ``REDOC_SETTINGS``
----------------------------------------------
Additionally, you can include some more settings in your ``settings.py`` file.
The possible settings and their default values are as follows:
See https://drf-yasg.readthedocs.io/en/stable/settings.html for details.
.. code:: python
SWAGGER_SETTINGS = {
# default inspector classes, see advanced documentation
'DEFAULT_AUTO_SCHEMA_CLASS': 'drf_yasg.inspectors.SwaggerAutoSchema',
'DEFAULT_FIELD_INSPECTORS': [
'drf_yasg.inspectors.CamelCaseJSONFilter',
'drf_yasg.inspectors.ReferencingSerializerInspector',
'drf_yasg.inspectors.RelatedFieldInspector',
'drf_yasg.inspectors.ChoiceFieldInspector',
'drf_yasg.inspectors.FileFieldInspector',
'drf_yasg.inspectors.DictFieldInspector',
'drf_yasg.inspectors.SimpleFieldInspector',
'drf_yasg.inspectors.StringDefaultFieldInspector',
],
'DEFAULT_FILTER_INSPECTORS': [
'drf_yasg.inspectors.CoreAPICompatInspector',
],
'DEFAULT_PAGINATOR_INSPECTORS': [
'drf_yasg.inspectors.DjangoRestResponsePagination',
'drf_yasg.inspectors.CoreAPICompatInspector',
],
# default api Info if none is otherwise given; should be an import string to an openapi.Info object
'DEFAULT_INFO': None,
# default API url if none is otherwise given
'DEFAULT_API_URL': None,
'USE_SESSION_AUTH': True, # add Django Login and Django Logout buttons, CSRF token to swagger UI page
'LOGIN_URL': getattr(django.conf.settings, 'LOGIN_URL', None), # URL for the login button
'LOGOUT_URL': getattr(django.conf.settings, 'LOGOUT_URL', None), # URL for the logout button
# Swagger security definitions to include in the schema;
# see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-definitions-object
'SECURITY_DEFINITIONS': {
'basic': {
'type': 'basic'
}
},
# url to an external Swagger validation service; defaults to 'http://online.swagger.io/validator/'
# set to None to disable the schema validation badge in the UI
'VALIDATOR_URL': '',
# swagger-ui configuration settings, see https://github.com/swagger-api/swagger-ui/blob/112bca906553a937ac67adc2e500bdeed96d067b/docs/usage/configuration.md#parameters
'OPERATIONS_SORTER': None,
'TAGS_SORTER': None,
'DOC_EXPANSION': 'list',
'DEEP_LINKING': False,
'SHOW_EXTENSIONS': True,
'DEFAULT_MODEL_RENDERING': 'model',
'DEFAULT_MODEL_DEPTH': 3,
}
.. code:: python
REDOC_SETTINGS = {
# ReDoc UI configuration settings, see https://github.com/Rebilly/ReDoc#redoc-tag-attributes
'LAZY_RENDERING': True,
'HIDE_HOSTNAME': False,
'EXPAND_RESPONSES': 'all',
'PATH_IN_MIDDLE': False,
}
3. Caching
==========

View File

@ -9,158 +9,6 @@ Custom schema generation
If the default spec generation does not quite match what you were hoping to achieve, ``drf-yasg`` provides some
custom behavior hooks by default.
*********************
Swagger spec 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>`__.
Beause 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.
.. versionadded:: 1.2
Base path and versioning support.
.. _custom-spec-swagger-auto-schema:
**************************************
@ -430,6 +278,3 @@ A second example, of a :class:`~.inspectors.FieldInspector` that removes the ``t
This means that you should generally avoid view or method-specific ``FieldInspector``\ s if you are dealing with
references (a.k.a named models), because you can never know which view will be the first to generate the schema
for a given serializer.
.. _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

View File

@ -12,6 +12,8 @@ drf-yasg
readme.rst
rendering.rst
openapi.rst
security.rst
custom_spec.rst
custom_ui.rst
settings.rst

163
docs/openapi.rst 100644
View File

@ -0,0 +1,163 @@
.. |br| raw:: html
<br />
**********************
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>`__.
Beause 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.
.. versionadded:: 1.2
Base path and versioning support.
.. _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

49
docs/security.rst 100644
View File

@ -0,0 +1,49 @@
*********************************
Describing authentication schemes
*********************************
When using the `swagger-ui` frontend, it is possible to interact with the API described by your Swagger document.
This interaction might require authentication, which you will have to describe in order to make `swagger-ui` work
with it.
--------------------
Security definitions
--------------------
The first step that you have to do is add a :ref:`SECURITY_DEFINITIONS <security-definitions-settings>` setting
to declare all authentication schemes supported by your API.
For example, the definition for a simple API accepting HTTP basic auth and `Authorization` header API tokens would be:
.. code-block:: python
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'Basic': {
'type': 'basic'
},
'Bearer': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
}
}
}
---------------------
Security requirements
---------------------
The second step is specifying, for each endpoint, which authentication mechanism can be used for interacting with it.
See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object for details.
By default, a top-level `security` that accepts all the declared security definitions is generated.
For the example above, that would be :code:`[{'Basic': []}, {'Bearer': []}]`. This can be overriden using the
:ref:`SECURITY_REQUIREMENTS <security-definitions-settings>` setting.
Operation-level overrides can be added using the ``security`` parameter of
:ref:`@swagger_auto_schema <custom-spec-swagger-auto-schema>`.

View File

@ -140,6 +140,9 @@ URL for the Django Logout action when using `USE_SESSION_AUTH`_.
**Default**: :python:`django.conf.settings.LOGOUT_URL`
.. _security-definitions-settings:
SECURITY_DEFINITIONS
--------------------
@ -154,6 +157,14 @@ See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#sec
'type': 'basic'
}
SECURITY_REQUIREMENTS
---------------------
Global security requirements. If :python:`None`, all schemes in ``SECURITY_DEFINITIONS`` are accepted. |br|
See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#securityRequirementObject.
**Default**: :python:`None`
.. _swagger-ui-settings:
Swagger UI settings

80
package-lock.json generated
View File

@ -38,9 +38,9 @@
}
},
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
"optional": true
},
"core-js": {
@ -73,9 +73,9 @@
"integrity": "sha1-8TyUAhQdoJ50rfTmN5jXkiBEOPI="
},
"es6-promise": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz",
"integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng=="
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.2.tgz",
"integrity": "sha512-LSas5vsuA6Q4nEdf9wokY5/AJYXry98i0IzXsv49rYsgDGDNDPbqAYR1Pe23iFxygfbGZNR/5VrHXBCh2BhvUQ=="
},
"esprima": {
"version": "4.0.0",
@ -145,9 +145,9 @@
"requires": {
"call-me-maybe": "1.0.1",
"debug": "3.1.0",
"es6-promise": "4.1.1",
"es6-promise": "4.2.2",
"js-yaml": "3.10.0",
"ono": "4.0.2",
"ono": "4.0.3",
"z-schema": "3.19.0"
}
},
@ -166,15 +166,20 @@
"resolved": "https://registry.npmjs.org/lunr/-/lunr-1.0.0.tgz",
"integrity": "sha1-XJJ2ySyRrDWpJBtQGNRnI9kuL18="
},
"mark.js": {
"version": "8.11.1",
"resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz",
"integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"ono": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/ono/-/ono-4.0.2.tgz",
"integrity": "sha512-EFXJFoeF+KkZW4lwmcPMKHp2ZU7o6CM+ccX2nPbEJKiJIdyqbIcS1v6pmNgeNJ6x4/vEYn0/8oz66qXSPnnmSQ==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/ono/-/ono-4.0.3.tgz",
"integrity": "sha512-7QIxG4UB00H7CR7fhXC/U7VhB5DK9wsYLwaYBui1JmQoXtLkhIBn3fbuk6FgAP+ctWeBsWVTM+R/bThvUZN+ww==",
"requires": {
"format-util": "1.0.3"
}
@ -190,9 +195,9 @@
"integrity": "sha512-RNC5tX/JMRYR+qVdJTEAWnRxw0Yf9lvbO8lTuAOvgDODkiA8lveTSkvrNMhmaGKEyimJpJl+myb/syVS9YyPuw=="
},
"prismjs": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.9.0.tgz",
"integrity": "sha1-+j4tntw8OIfB8fMJXUHx+bQgDw8=",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.10.0.tgz",
"integrity": "sha1-d+UYfCrmsyU/zDEwKc8l/lN3hyE=",
"requires": {
"clipboard": "1.7.1"
}
@ -217,9 +222,9 @@
}
},
"redoc": {
"version": "1.19.3",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-1.19.3.tgz",
"integrity": "sha1-DfPx+6S92G/+nGIAEzBxUjytVec=",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/redoc/-/redoc-1.20.0.tgz",
"integrity": "sha1-1c16xoQKJ8/7RzvSiYAFUq+CHq8=",
"requires": {
"core-js": "2.5.3",
"dropkickjs": "2.1.10",
@ -228,21 +233,16 @@
"json-pointer": "0.6.0",
"json-schema-ref-parser": "3.3.1",
"lunr": "1.0.0",
"mark.js": "github:julmot/mark.js#714c9523feca999267f1758da8cfd92d077105d0",
"mark.js": "8.11.1",
"openapi-sampler": "0.4.3",
"perfect-scrollbar": "0.8.1",
"prismjs": "1.9.0",
"prismjs": "1.10.0",
"remarkable": "1.7.1",
"scrollparent": "2.0.1",
"slugify": "1.2.6",
"stream-http": "2.7.2",
"slugify": "1.2.9",
"stream-http": "2.8.0",
"ts-helpers": "1.1.2",
"zone.js": "0.8.18"
},
"dependencies": {
"mark.js": {
"version": "github:julmot/mark.js#714c9523feca999267f1758da8cfd92d077105d0"
}
"zone.js": "0.8.20"
}
},
"remarkable": {
@ -282,9 +282,9 @@
"optional": true
},
"slugify": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.2.6.tgz",
"integrity": "sha512-796YAGnzEnLKQHAFf7H2q1nsjY/9qywSnF9ZkMUbs9he4aZaXO/zFUow0LZ95sBAiQjOX1EmGl23gTYaswiNaQ=="
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.2.9.tgz",
"integrity": "sha512-n0cdJ+kN3slJu8SbZXt/EHjljBqF6MxvMGSg/NPpBzoY7yyXoH38wp/ox20a1JaG1KgmdTN5Lf3aS9+xB2Y2aQ=="
},
"sprintf-js": {
"version": "1.0.3",
@ -292,9 +292,9 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"stream-http": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
"integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz",
"integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==",
"requires": {
"builtin-status-codes": "3.0.0",
"inherits": "2.0.3",
@ -312,9 +312,9 @@
}
},
"swagger-ui-dist": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.9.1.tgz",
"integrity": "sha1-zLjtVjHJY8Q4jCgFxCg0t69u+eo="
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.9.2.tgz",
"integrity": "sha1-XuK7G2IFPC3ydGnlVZDGX8AOidQ="
},
"tiny-emitter": {
"version": "2.0.2",
@ -362,16 +362,16 @@
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.19.0.tgz",
"integrity": "sha512-V94f3ODuluBS4kQLLjNhwoMek0dyIXCsvNu/A17dAyJ6sMhT5KkJQwSn07R0naByLIXJWMDk+ruMfI/3G3hS4Q==",
"requires": {
"commander": "2.12.2",
"commander": "2.13.0",
"lodash.get": "4.4.2",
"lodash.isequal": "4.5.0",
"validator": "9.2.0"
}
},
"zone.js": {
"version": "0.8.18",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz",
"integrity": "sha512-knKOBQM0oea3/x9pdyDuDi7RhxDlJhOIkeixXSiTKWLgs4LpK37iBc+1HaHwzlciHUKT172CymJFKo8Xgh+44Q=="
"version": "0.8.20",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.20.tgz",
"integrity": "sha512-FXlA37ErSXCMy5RNBcGFgCI/Zivqzr0D19GuvDxhcYIJc7xkFp6c29DKyODJu0Zo+EMyur/WPPgcBh1EHjB9jA=="
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "drf-yasg",
"dependencies": {
"redoc": "^1.19.3",
"swagger-ui-dist": "^3.9.1"
"redoc": "^1.20.0",
"swagger-ui-dist": "^3.9.2"
}
}

View File

@ -31,6 +31,7 @@ SWAGGER_DEFAULTS = {
'type': 'basic'
}
},
'SECURITY_REQUIREMENTS': None,
'LOGIN_URL': getattr(settings, 'LOGIN_URL', None),
'LOGOUT_URL': getattr(settings, 'LOGOUT_URL', None),
'VALIDATOR_URL': '',

View File

@ -94,7 +94,6 @@ class _OpenAPICodec(object):
:return: swagger spec as dict
:rtype: OrderedDict
"""
swagger.security_definitions = swagger_settings.SECURITY_DEFINITIONS
return swagger.as_odict()

View File

@ -197,10 +197,16 @@ class OpenAPISchemaGenerator(object):
if url is None and request is not None:
url = request.build_absolute_uri()
return openapi.Swagger(
swagger = openapi.Swagger(
info=self.info, paths=paths,
_url=url, _prefix=prefix, _version=self.version, **dict(components)
)
swagger.security_definitions = swagger_settings.SECURITY_DEFINITIONS
security_requirements = swagger_settings.SECURITY_REQUIREMENTS
if security_requirements is None:
security_requirements = [{security_scheme: [] for security_scheme in swagger_settings.SECURITY_DEFINITIONS}]
swagger.security = security_requirements
return swagger
def create_view(self, callback, method, request=None):
"""Create a view instance from a view callback as registered in urlpatterns.

View File

@ -27,6 +27,8 @@ class SwaggerAutoSchema(ViewInspector):
operation_id = self.get_operation_id(operation_keys)
description = self.get_description()
security = self.get_security()
assert security is None or isinstance(security, list), "security must be a list of securiy requirement objects"
tags = self.get_tags(operation_keys)
responses = self.get_responses()
@ -38,6 +40,7 @@ class SwaggerAutoSchema(ViewInspector):
parameters=parameters,
consumes=consumes,
tags=tags,
security=security
)
def get_request_body_parameters(self, consumes):
@ -286,6 +289,16 @@ class SwaggerAutoSchema(ViewInspector):
description = self._sch.get_description(self.path, self.method)
return description
def get_security(self):
"""Return a list of security requirements for this operation.
Returning an empty list marks the endpoint as unauthenticated (i.e. removes all accepted
authentication schemes). Returning ``None`` will inherit the top-level secuirty requirements.
:return: security requirements
:rtype: list"""
return self.overrides.get('security', None)
def get_tags(self, operation_keys):
"""Get a list of tags for this operation. Tags determine how operations relate with each other, and in the UI
each tag will show as a group containing the operations that use it.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,8 +13,8 @@ no_body = object()
def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_body=None, query_serializer=None,
manual_parameters=None, operation_id=None, operation_description=None, responses=None,
field_inspectors=None, filter_inspectors=None, paginator_inspectors=None,
manual_parameters=None, operation_id=None, operation_description=None, security=None,
responses=None, field_inspectors=None, filter_inspectors=None, paginator_inspectors=None,
**extra_overrides):
"""Decorate a view method to customize the :class:`.Operation` object generated from it.
@ -62,6 +62,9 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod
:param str operation_id: operation ID override; the operation ID must be unique accross the whole API
:param str operation_description: operation description override
:param str security: security requirements override; used to specify which authetication mechanism
is requried to call this API; an empty list marks the endpoint as unauthenticated (i.e. removes all accepted
authentication schemes), and ``None`` will inherit the top-level secuirty requirements
:param dict[str,(.Schema,.SchemaRef,.Response,str,Serializer)] responses: a dict of documented manual responses
keyed on response status code. If no success (``2xx``) response is given, one will automatically be
generated from the request body and http method. If any ``2xx`` response is given the automatic response is
@ -94,6 +97,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod
'manual_parameters': manual_parameters,
'operation_id': operation_id,
'operation_description': operation_description,
'security': security,
'responses': responses,
'filter_inspectors': list(filter_inspectors) if filter_inspectors else None,
'paginator_inspectors': list(paginator_inspectors) if paginator_inspectors else None,

View File

@ -19,13 +19,17 @@ class UserList(APIView):
serializer = UserSerializerrr(queryset, many=True)
return Response(serializer.data)
@swagger_auto_schema(operation_description="apiview post description override", request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['username'],
properties={
'username': openapi.Schema(type=openapi.TYPE_STRING)
},
))
@swagger_auto_schema(
operation_description="apiview post description override",
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['username'],
properties={
'username': openapi.Schema(type=openapi.TYPE_STRING)
},
),
security=[]
)
def post(self, request):
serializer = UserSerializerrr(request.data)
serializer.is_valid(raise_exception=True)

View File

@ -412,6 +412,7 @@ paths:
- application/json
tags:
- users
security: []
patch:
operationId: users_dummy
description: dummy operation
@ -1123,3 +1124,5 @@ definitions:
securityDefinitions:
basic:
type: basic
security:
- basic: []

View File

@ -67,3 +67,15 @@ def test_no_netloc(mock_schema_request):
swagger = generator.get_schema(mock_schema_request, public=True)
assert 'host' not in swagger and 'schemes' not in swagger
assert swagger['info']['version'] == 'v2'
def test_securiy_requirements(swagger_settings, mock_schema_request):
generator = OpenAPISchemaGenerator(
info=openapi.Info(title="Test generator", default_version="v1"),
version="v2",
url='',
)
swagger_settings['SECURITY_REQUIREMENTS'] = []
swagger = generator.get_schema(mock_schema_request, public=True)
assert swagger['security'] == []

View File

@ -1,10 +1,8 @@
#!/bin/bash
set -ev
npm update
npm install -g --prefix ./node_modules/redoc-alpha redoc@latest
cp node_modules/redoc/dist/redoc.min.js src/drf_yasg/static/drf-yasg/redoc/
cp node_modules/redoc-alpha/node_modules/redoc/bundles/redoc.standalone.js src/drf_yasg/static/drf-yasg/redoc-alpha/
cp -r node_modules/swagger-ui-dist src/drf_yasg/static/drf-yasg/
pushd src/drf_yasg/static/drf-yasg/swagger-ui-dist/ >/dev/null
rm -f package.json .npmignore README.md