From a211184478e6f0ca348312438c9c29d7b535b0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20V=C3=AEjdea?= Date: Wed, 24 Jan 2018 17:38:10 +0200 Subject: [PATCH] Add documentation about excluding endpoints Closes #50. --- docs/custom_spec.rst | 27 +++++++++++++++++++++++++-- docs/openapi.rst | 22 +++++++++++++++++++--- docs/rendering.rst | 2 -- src/drf_yasg/generators.py | 3 +++ src/drf_yasg/inspectors/view.py | 4 ++-- src/drf_yasg/utils.py | 15 ++++++--------- 6 files changed, 55 insertions(+), 18 deletions(-) diff --git a/docs/custom_spec.rst b/docs/custom_spec.rst index 2bb8ef4..2d940ae 100644 --- a/docs/custom_spec.rst +++ b/docs/custom_spec.rst @@ -9,6 +9,31 @@ 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. +.. _custom-spec-excluding-endpoints: + +******************* +Excluding endpoints +******************* + +You can prevent a view from being included in the Swagger view by setting its class-level ``swagger_schema`` +attribute to ``None``, or you can prevent an operation from being included by setting its ``auto_schema`` override +to none in :ref:`@swagger_auto_schema `: + +.. code-block:: python + + class UserList(APIView): + swagger_schema = None + + # all methods of the UserList class will be excluded + ... + + # only the GET method will be shown in Swagger + @swagger_auto_schema(method='put', auto_schema=None) + @swagger_auto_schema(methods=['get'], ...) + @api_view(['GET', 'PUT']) + def user_detail(request, pk): + pass + .. _custom-spec-swagger-auto-schema: ************************************** @@ -200,8 +225,6 @@ This custom generator can be put to use by setting it as the :attr:`.generator_c ``Inspector`` classes --------------------- -.. versionadded:: 1.1 - For customizing behavior related to specific field, serializer, filter or paginator classes you can implement the :class:`~.inspectors.FieldInspector`, :class:`~.inspectors.SerializerInspector`, :class:`~.inspectors.FilterInspector`, :class:`~.inspectors.PaginatorInspector` classes and use them with diff --git a/docs/openapi.rst b/docs/openapi.rst index 5d62426..3669d3d 100644 --- a/docs/openapi.rst +++ b/docs/openapi.rst @@ -6,7 +6,6 @@ Functional overview ********************** - ------------------------------ OpenAPI specification overview ------------------------------ @@ -155,9 +154,26 @@ This section describes where information is sourced from when using the default Other versioning schemes are not presently supported. +--------------------- +A note on limitations +--------------------- -.. versionadded:: 1.2 - Base path and versioning support. +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 `, to prevent ``get_serializer`` from being called on + the view +* :ref:`exclude your endpoint from introspection ` .. _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 diff --git a/docs/rendering.rst b/docs/rendering.rst index 043fe14..17cd4f4 100644 --- a/docs/rendering.rst +++ b/docs/rendering.rst @@ -41,8 +41,6 @@ You can use your custom renderer classes as kwargs to :meth:`.SchemaView.as_cach Management command ****************** -.. versionadded:: 1.1.1 - If you only need a swagger spec file in YAML or JSON format, you can use the ``generate_swagger`` management command to get it without having to start the web server: diff --git a/src/drf_yasg/generators.py b/src/drf_yasg/generators.py index 85aa2da..55a51a5 100644 --- a/src/drf_yasg/generators.py +++ b/src/drf_yasg/generators.py @@ -45,6 +45,9 @@ class EndpointEnumerator(_EndpointEnumerator): if version and version not in namespace.split(':'): return False + if getattr(callback.cls, 'swagger_schema', object()) is None: + return False + return True def replace_version(self, path, callback): diff --git a/src/drf_yasg/inspectors/view.py b/src/drf_yasg/inspectors/view.py index 0e5d46f..549d39e 100644 --- a/src/drf_yasg/inspectors/view.py +++ b/src/drf_yasg/inspectors/view.py @@ -96,8 +96,8 @@ class SwaggerAutoSchema(ViewInspector): if body_override is no_body: return None if self.method not in self.body_methods: - raise SwaggerGenerationError("request_body can only be applied to PUT, PATCH or POST views; " - "are you looking for query_serializer or manual_parameters?") + raise SwaggerGenerationError("request_body can only be applied to (" + ','.join(self.body_methods) + + "); are you looking for query_serializer or manual_parameters?") if isinstance(body_override, openapi.Schema.OR_REF): return body_override return force_serializer_instance(body_override) diff --git a/src/drf_yasg/utils.py b/src/drf_yasg/utils.py index 32b2dbc..a366473 100644 --- a/src/drf_yasg/utils.py +++ b/src/drf_yasg/utils.py @@ -12,8 +12,10 @@ logger = logging.getLogger(__name__) #: used to forcibly remove the body of a request via :func:`.swagger_auto_schema` no_body = object() +unset = object() -def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_body=None, query_serializer=None, + +def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_body=None, query_serializer=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): @@ -24,17 +26,11 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod The `auto_schema` and `operation_description` arguments take precendence over view- or method-level values. - .. versionchanged:: 1.1 - Added the ``extra_overrides`` and ``operatiod_id`` parameters. - - .. versionchanged:: 1.1 - Added the ``field_inspectors``, ``filter_inspectors`` and ``paginator_inspectors`` parameters. - :param str method: for multi-method views, the http method the options should apply to :param list[str] methods: for multi-method views, the http methods the options should apply to :param .inspectors.SwaggerAutoSchema auto_schema: custom class to use for generating the Operation object; this overrides both the class-level ``swagger_schema`` attribute and the ``DEFAULT_AUTO_SCHEMA_CLASS`` - setting + setting, and can be set to ``None`` to prevent this operation from being generated :param .Schema,.SchemaRef,.Serializer request_body: custom request body, or :data:`.no_body`. The value given here will be used as the ``schema`` property of a :class:`.Parameter` with ``in: 'body'``. @@ -92,7 +88,6 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod 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 = { - 'auto_schema': auto_schema, 'request_body': request_body, 'query_serializer': query_serializer, 'manual_parameters': manual_parameters, @@ -105,6 +100,8 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=None, request_bod 'field_inspectors': list(field_inspectors) if field_inspectors else None, } data = filter_none(data) + if auto_schema is not unset: + data['auto_schema'] = auto_schema data.update(extra_overrides) if not data: # pragma: no cover # no overrides to set, no use in doing more work