From *drf-yasg* to OpenAPI 3 ============================ `drf-yasg`__ is an excellent library and the most popular choice for generating OpenAPI 2.0 (formerly known as Swagger 2.0) schemas with `Django REST Framework`__. Unfortunately, it currently does not provide support for OpenAPI 3.x. Migration from *drf-yasg* to *drf-spectacular* requires some modifications, the complexity of which depends on what features are being used. __ https://pypi.org/project/drf-yasg __ https://pypi.org/project/djangorestframework/ .. note:: In contrast to *drf-yasg*, we don't package Redoc & Swagger UI but serve them via hyperlinked CDNs instead. If you want or need to serve those files yourself, you can do that with the optional `drf-spectacular-sidecar `_ package. See :ref:`installation instructions ` for further details. Decorators ---------- - :py:func:`@swagger_auto_schema ` is largely equivalent to :py:func:`@extend_schema `. - ``operation_description`` argument is called ``description`` - ``operation_summary`` argument is called ``summary`` - ``manual_parameters`` and ``query_serializer`` arguments are merged into a single ``parameters`` argument - ``security`` argument is called ``auth`` - ``request_body`` arguments is called ``request`` - Use ``None`` instead of :py:class:`drf_yasg.utils.no_body` - ``method`` argument doesn't exist, use ``methods`` instead (also supported by *drf-yasg*) - ``auto_schema`` has no equivalent. - ``extra_overrides`` has no equivalent. - ``field_inspectors`` has no equivalent. - ``filter_inspectors`` has no equivalent. - ``paginator_inspectors`` has no equivalent. - Additional arguments are also available: ``exclude``, ``operation``, ``versions``, ``examples``. - :py:func:`@swagger_serializer_method ` is equivalent to :py:func:`@extend_schema_field `. - ``component_name`` can be provided to break the field out as a separate component. - :py:func:`@extend_schema_serializer ` is available for overriding behavior of serializers. - Instead of using :py:func:`@method_decorator `, use :py:func:`@extend_schema_view `. - Instead of using ``swagger_schema_field``, use :py:func:`@extend_schema_field ` or :py:func:`@extend_schema_serializer `. Helper Classes -------------- - :py:class:`~drf_yasg.openapi.Parameter` is roughly equivalent to :py:class:`~drf_spectacular.utils.OpenApiParameter`. - ``in_`` argument is called ``location``. - ``schema`` argument should be passed as ``type``. - ``format`` argument is merged into ``type`` argument by using :py:class:`OpenApiTypes `. - setting the ``many`` argument to ``True`` causes the argument to take an array of values, and generates a schema similar to using the drf_yasg ``Items`` class on the ``items`` property. The type of the items in the array are defined by the ``type`` argument. - :py:class:`~drf_yasg.openapi.Response` is largely identical to :py:class:`~drf_spectacular.utils.OpenApiResponse`. - ``schema`` argument is called ``response`` - Order of arguments differs, so use keyword arguments. - :py:class:`~drf_spectacular.utils.OpenApiExample` is available for providing ``examples`` to :py:func:`@extend_schema `. - :py:class:`~drf_yasg.openapi.Schema` is not required and can be eliminated. Use a plain :py:class:`dict` instead. Types & Formats --------------- In place of separate ``drf_yasg.openapi.TYPE_*`` and ``drf_yasg.openapi.FORMAT_*`` constants, ``drf-spectacular`` provides the :py:class:`~drf_spectacular.types.OpenApiTypes` enum: - :py:data:`~drf_yasg.openapi.TYPE_BOOLEAN` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.BOOL`, but you can use :py:class:`bool`. - :py:data:`~drf_yasg.openapi.TYPE_FILE` should be replaced by :py:attr:`~drf_spectacular.types.OpenApiTypes.BINARY` - :py:data:`~drf_yasg.openapi.TYPE_INTEGER` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.INT`, but you can use :py:class:`int`. - :py:data:`~drf_yasg.openapi.TYPE_INTEGER` with :py:data:`~drf_yasg.openapi.FORMAT_INT32` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.INT32` - :py:data:`~drf_yasg.openapi.TYPE_INTEGER` with :py:data:`~drf_yasg.openapi.FORMAT_INT64` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.INT64` - :py:data:`~drf_yasg.openapi.TYPE_NUMBER` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.NUMBER` - :py:data:`~drf_yasg.openapi.TYPE_NUMBER` with :py:data:`~drf_yasg.openapi.FORMAT_FLOAT` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.FLOAT`, but you can use :py:class:`float`. - :py:data:`~drf_yasg.openapi.TYPE_NUMBER` with :py:data:`~drf_yasg.openapi.FORMAT_DOUBLE` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.DOUBLE` (or :py:attr:`~drf_spectacular.types.OpenApiTypes.DECIMAL`, but you can use :py:class:`~decimal.Decimal`) - :py:data:`~drf_yasg.openapi.TYPE_OBJECT` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.OBJECT`, but you can use :py:class:`dict`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.STR`, but you can use :py:class:`str`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_BASE64` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.BYTE` (which is base64 encoded). - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_BINARY` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.BINARY`, but you can use :py:class:`bytes`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_DATETIME` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.DATETIME`, but you can use :py:class:`datetime.datetime`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_DATE` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.DATE`, but you can use :py:class:`datetime.date`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_EMAIL` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.EMAIL` - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_IPV4` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.IP4`, but you can use :py:class:`ipaddress.IPv4Address`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_IPV6` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.IP6`, but you can use :py:class:`ipaddress.IPv6Address`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_PASSWORD` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.PASSWORD` - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_URI` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.URI` - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_UUID` is called :py:attr:`~drf_spectacular.types.OpenApiTypes.UUID`, but you can use :py:class:`uuid.UUID`. - :py:data:`~drf_yasg.openapi.TYPE_STRING` with :py:data:`~drf_yasg.openapi.FORMAT_SLUG` has no direct equivalent. Use :py:attr:`~drf_spectacular.types.OpenApiTypes.STR` or :py:class:`str` instead. - :py:data:`~drf_yasg.openapi.TYPE_ARRAY` is handled by providing :py:attr:`~drf_spectacular.utils.OpenApiParameter` with ``many=True`` as a parameter. There is no need to set the ``items`` property on the parameter - the presence of ``many=True`` turns the parameter into an array parameter. - The following additional types are also available: - :py:attr:`~drf_spectacular.types.OpenApiTypes.ANY` for which you can use :py:class:`typing.Any`. - :py:attr:`~drf_spectacular.types.OpenApiTypes.DURATION` for which you can use :py:class:`datetime.timedelta`. - :py:attr:`~drf_spectacular.types.OpenApiTypes.HOSTNAME` - :py:attr:`~drf_spectacular.types.OpenApiTypes.IDN_EMAIL` - :py:attr:`~drf_spectacular.types.OpenApiTypes.IDN_HOSTNAME` - :py:attr:`~drf_spectacular.types.OpenApiTypes.IRI_REF` - :py:attr:`~drf_spectacular.types.OpenApiTypes.IRI` - :py:attr:`~drf_spectacular.types.OpenApiTypes.JSON_PTR_REL` - :py:attr:`~drf_spectacular.types.OpenApiTypes.JSON_PTR` - :py:attr:`~drf_spectacular.types.OpenApiTypes.NONE` for which you can use :py:data:`None`. - :py:attr:`~drf_spectacular.types.OpenApiTypes.REGEX` - :py:attr:`~drf_spectacular.types.OpenApiTypes.TIME` for which you can use :py:class:`datetime.time`. - :py:attr:`~drf_spectacular.types.OpenApiTypes.URI_REF` - :py:attr:`~drf_spectacular.types.OpenApiTypes.URI_TPL` Parameter Location ------------------ ``drf_yasg.openapi.IN_*`` constants are roughly equivalent to constants defined on the :py:class:`~drf_spectacular.utils.OpenApiParameter` class: - :py:data:`~drf_yasg.openapi.IN_PATH` is called :py:attr:`~drf_spectacular.utils.OpenApiParameter.PATH` - :py:data:`~drf_yasg.openapi.IN_QUERY` is called :py:attr:`~drf_spectacular.utils.OpenApiParameter.QUERY` - :py:data:`~drf_yasg.openapi.IN_HEADER` is called :py:attr:`~drf_spectacular.utils.OpenApiParameter.HEADER` - :py:data:`~drf_yasg.openapi.IN_BODY` and :py:data:`~drf_yasg.openapi.IN_FORM` have no direct equivalent. Instead you can use ``@extend_schema(request={"": ...})``. - :py:attr:`~drf_spectacular.utils.OpenApiParameter.COOKIE` is also available. Docstring Parsing ----------------- *drf-yasg* has some special handling for docstrings that is not supported by *drf-spectacular*. It attempts to split the first line from the rest of the docstring to use as the operation summary, and the remainder is used as the operation description. *drf-spectacular* uses the entire docstring as the description. Use the ``summary`` and ``description`` arguments of :py:func:`@extend_schema ` instead. Optionally, the docstring can still be used to populate the operation description. .. code-block:: python # Supported by drf-yasg: class UserViewSet(ViewSet): def list(self, request): """ List all the users. Return a list of all usernames in the system. """ ... # Updated for drf-spectacular using decorator for description: class UserViewSet(ViewSet): @extend_schema( summary="List all the users.", description="Return a list of all usernames in the system.", ) def list(self, request): ... # Updated for drf-spectacular using docstring for description: class UserViewSet(ViewSet): @extend_schema(summary="List all the users.") def list(self, request): """Return a list of all usernames in the system.""" ... In addition, *drf-yasg* also supports `named sections`__, but these are not supported by *drf-spectacular*. Again, use the ``summary`` and ``description`` arguments of :py:func:`@extend_schema ` instead: __ https://www.django-rest-framework.org/coreapi/schemas/#schemas-as-documentation .. code-block:: python # Supported by drf-yasg: class UserViewSet(ViewSet): """ list: List all the users. Return a list of all usernames in the system. retrieve: Retrieve user Get details of a specific user """ ... # Updated for drf-spectacular using decorator for description: @extend_schema_view( list=extend_schema( summary="List all the users.", description="Return a list of all usernames in the system.", ), retrieve=extend_schema( summary="Retrieve user", description="Get details of a specific user", ), ) class UserViewSet(ViewSet): ... Authentication -------------- In *drf-yasg* it was necessary to :doc:`manually describe authentication schemes `. In *drf-spectacular* there is support for auto-generating the security definitions for a number of authentication classes built in to DRF as well as other popular third-party packages. :py:class:`~drf_spectacular.extensions.OpenApiAuthenticationExtension` is available to help tie in custom authentication clasees -- see the :ref:`customization guide `. Compatibility ------------- For compatibility, the following features of *drf-yasg* have been implemented: - ``ref_name`` on ``Serializer`` ``Meta`` classes is supported (excluding inlining with ``ref_name=None``) - See :ref:`drf-yasg's documentation ` for further details. - The equivalent in ``drf-spectacular`` is ``@extend_schema_serializer(component_name="...")`` - ``swagger_fake_view`` is available as attribute on views to signal schema generation