parent
f81795d745
commit
68b0dda0b9
56
README.rst
56
README.rst
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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**
|
||||||
*********
|
*********
|
||||||
|
|
|
||||||
|
|
@ -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 ...
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue