Clean up and release 1.1.3

openapi3 1.1.3
Cristi Vîjdea 2018-01-02 22:07:33 +01:00
parent f81795d745
commit 68b0dda0b9
6 changed files with 99 additions and 59 deletions

View File

@ -94,42 +94,42 @@ In ``settings.py``:
.. code:: python .. code:: python
INSTALLED_APPS = [ INSTALLED_APPS = [
... ...
'drf_yasg', 'drf_yasg',
... ...
] ]
In ``urls.py``: In ``urls.py``:
.. code:: python .. code:: python
... ...
from drf_yasg.views import get_schema_view from drf_yasg.views import get_schema_view
from drf_yasg import openapi from drf_yasg import openapi
... ...
schema_view = get_schema_view( schema_view = get_schema_view(
openapi.Info( openapi.Info(
title="Snippets API", title="Snippets API",
default_version='v1', default_version='v1',
description="Test description", description="Test description",
terms_of_service="https://www.google.com/policies/terms/", terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"), contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"), license=openapi.License(name="BSD License"),
), ),
validators=['ssv', 'flex'], validators=['ssv', 'flex'],
public=True, public=True,
permission_classes=(permissions.AllowAny,), permission_classes=(permissions.AllowAny,),
) )
urlpatterns = [ urlpatterns = [
url(r'^swagger(?P<format>.json|.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'), url(r'^swagger(?P<format>.json|.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'),
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'), url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'), url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'),
... ...
] ]
This exposes 4 cached, validated and publicly available endpoints: This exposes 4 cached, validated and publicly available endpoints:

View File

@ -3,6 +3,14 @@ Changelog
######### #########
*********
**1.1.3**
*********
- **FIXED:** schema view cache will now always ``Vary`` on the ``Cookie`` and ``Authentication`` (the
``Vary`` header was previously only added if ``public`` was set to ``True``) - this fixes issues related to Django
authentication in ``swagger-ui`` and ``CurrentUserDefault`` values in the schema
********* *********
**1.1.2** **1.1.2**
********* *********

View File

@ -58,3 +58,30 @@ See the command help for more advanced options:
usage: manage.py generate_swagger [-h] [--version] [-v {0,1,2,3}] usage: manage.py generate_swagger [-h] [--version] [-v {0,1,2,3}]
... more options ... ... more options ...
.. Note::
The :ref:`DEFAULT_INFO <default-swagger-settings>` setting must be defined when using the ``generate_swagger``
command. For example, the :ref:`README quickstart <readme-quickstart>` code could be modified as such:
In ``settings.py``:
.. code:: python
SWAGGER_SETTINGS = {
'DEFAULT_INFO': 'import.path.to.urls.api_info',
}
In ``urls.py``:
.. code:: python
api_info = openapi.Info(
title="Snippets API",
... other arguments ...
)
schema_view = get_schema_view(
# the info argument is no longer needed here as it will be picked up from DEFAULT_INFO
... other arguments ...
)

View File

@ -94,6 +94,8 @@ Paginator inspectors given to :func:`@swagger_auto_schema <.swagger_auto_schema>
Swagger document attributes Swagger document attributes
=========================== ===========================
.. _default-swagger-settings:
DEFAULT_INFO DEFAULT_INFO
------------ ------------

View File

@ -4,6 +4,7 @@ from collections import OrderedDict
from rest_framework import serializers, status from rest_framework import serializers, status
from rest_framework.mixins import DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.mixins import DestroyModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.views import APIView
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -41,7 +42,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod
the `manual_parameters` argument. the `manual_parameters` argument.
If a ``Serializer`` class or instance is given, it will be automatically converted into a :class:`.Schema` If a ``Serializer`` class or instance is given, it will be automatically converted into a :class:`.Schema`
used as a ``body`` :class:`.Parameter`, or into a list of ``form`` :class:`.Parameter`\ s, as appropriate. used as a ``body`` :class:`.Parameter`, or into a list of ``form`` :class:`.Parameter`\ s, as appropriate.
:param .Serializer query_serializer: if you use a ``Serializer`` to parse query parameters, you can pass it here :param .Serializer query_serializer: if you use a ``Serializer`` to parse query parameters, you can pass it here
and have :class:`.Parameter` objects be generated automatically from it. and have :class:`.Parameter` objects be generated automatically from it.
@ -85,6 +86,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod
""" """
def decorator(view_method): def decorator(view_method):
assert not any(hm in extra_overrides for hm in APIView.http_method_names), "HTTP method names not allowed here"
data = { data = {
'auto_schema': auto_schema, 'auto_schema': auto_schema,
'request_body': request_body, 'request_body': request_body,
@ -97,48 +99,52 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod
'paginator_inspectors': list(paginator_inspectors) if paginator_inspectors else None, 'paginator_inspectors': list(paginator_inspectors) if paginator_inspectors else None,
'field_inspectors': list(field_inspectors) if field_inspectors else None, 'field_inspectors': list(field_inspectors) if field_inspectors else None,
} }
data = {k: v for k, v in data.items() if v is not None} data = filter_none(data)
data.update(extra_overrides) data.update(extra_overrides)
if not data: # pragma: no cover
# no overrides to set, no use in doing more work
return
# if the method is a detail_route or list_route, it will have a bind_to_methods attribute # if the method is a detail_route or list_route, it will have a bind_to_methods attribute
bind_to_methods = getattr(view_method, 'bind_to_methods', []) bind_to_methods = getattr(view_method, 'bind_to_methods', [])
# if the method is actually a function based view (@api_view), it will have a 'cls' attribute # if the method is actually a function based view (@api_view), it will have a 'cls' attribute
view_cls = getattr(view_method, 'cls', None) view_cls = getattr(view_method, 'cls', None)
http_method_names = getattr(view_cls, 'http_method_names', []) http_method_names = getattr(view_cls, 'http_method_names', [])
if bind_to_methods or http_method_names:
available_methods = http_method_names + bind_to_methods
existing_data = getattr(view_method, '_swagger_auto_schema', {})
_methods = methods
if methods or method:
assert bool(methods) != bool(method), "specify either method or methods"
assert not isinstance(methods, str), "`methods` expects to receive a list of methods;" \
" use `method` for a single argument"
if method:
_methods = [method.lower()]
else:
_methods = [mth.lower() for mth in methods]
assert all(mth in available_methods for mth in _methods), "http method not bound to view"
assert not any(mth in existing_data for mth in _methods), "http method defined multiple times"
if available_methods:
# detail_route, list_route or api_view # detail_route, list_route or api_view
assert bool(http_method_names) != bool(bind_to_methods), "this should never happen" assert bool(http_method_names) != bool(bind_to_methods), "this should never happen"
available_methods = http_method_names + bind_to_methods
existing_data = getattr(view_method, '_swagger_auto_schema', {})
if http_method_names:
_route = "api_view"
else:
_route = "detail_route" if view_method.detail else "list_route"
_methods = methods
if len(available_methods) > 1: if len(available_methods) > 1:
assert methods or method, \ assert _methods, \
"on multi-method %s, you must specify swagger_auto_schema on a per-method basis " \ "on multi-method api_view, detail_route or list_route, you must specify swagger_auto_schema on " \
"using one of the `method` or `methods` arguments" % _route "a per-method basis using one of the `method` or `methods` arguments"
assert bool(methods) != bool(method), "specify either method or methods"
assert not isinstance(methods, str), "`methods` expects to receive a list of methods;" \
" use `method` for a single argument"
if method:
_methods = [method.lower()]
else:
_methods = [mth.lower() for mth in methods]
assert not any(mth in existing_data for mth in _methods), "method defined multiple times"
assert all(mth in available_methods for mth in _methods), "method not bound to %s" % _route
existing_data.update((mth.lower(), data) for mth in _methods)
else: else:
existing_data[available_methods[0]] = data # for a single-method view we assume that single method as the decorator target
_methods = _methods or available_methods
existing_data.update((mth.lower(), data) for mth in _methods)
view_method._swagger_auto_schema = existing_data view_method._swagger_auto_schema = existing_data
else: else:
assert method is None and methods is None, \ assert not _methods, \
"the methods argument should only be specified when decorating a detail_route or list_route; you " \ "the methods argument should only be specified when decorating a detail_route or list_route; you " \
"should also ensure that you put the swagger_auto_schema decorator AFTER (above) the _route decorator" "should also ensure that you put the swagger_auto_schema decorator AFTER (above) the _route decorator"
assert not existing_data, "a single view method should only be decorated once"
view_method._swagger_auto_schema = data view_method._swagger_auto_schema = data
return view_method return view_method

View File

@ -52,10 +52,7 @@ def test_caching(client, validate_schema):
prev_schema = None prev_schema = None
for i in range(3): for i in range(3):
_validate_ui_schema_view(client, '/cached/redoc/', 'redoc/redoc.min.js') _validate_text_schema_view(client, validate_schema, '/cached/swagger.yaml', yaml_sane_load)
_validate_text_schema_view(client, validate_schema, '/cached/redoc/?format=openapi', json.loads)
_validate_ui_schema_view(client, '/cached/swagger/', 'swagger-ui-dist/swagger-ui-bundle.js')
_validate_text_schema_view(client, validate_schema, '/cached/swagger/?format=openapi', json.loads)
json_schema = client.get('/cached/swagger.json') json_schema = client.get('/cached/swagger.json')
assert json_schema.status_code == 200 assert json_schema.status_code == 200