Целью этой статьи является демонстрация возможностей drf-spectacular для документирования API и основного набора техник, которые покроют большую часть сценариев использования. Мы настроим генерацию документации и рассмотрим все основные способы гибкой настройки отображения.

Почему именно DRF Spectacular?

drf-spectacular - единственный проект, который сейчас активно поддерживается. django-rest-swagger и drf-yasg устарели и не обновлялись уже пару-тройку лет.

Как установить и добавить DRF Spectacular в проект?

Сначала устанавливаем сам пакет через pip install drf-spectacular

После чего добавляем в INSTALLED_APPS

 INSTALLED_APPS = [     
    # ВСЕ ВАШИ ПРИЛОЖЕНИЯ     
    'drf_spectacular', 
]

Далее необходимо добавить DEFAULT_SCHEMA_CLASS в настройки REST_FRAMEWORK в settings.py. Этот класс будет отвечать за генерацию самой схемы. В некоторых ситуациях мы можем прописать здесь свой класс для добавления дополнительной функциональности.

REST_FRAMEWORK = {     
    # ВАШИ НАСТРОЙКИ     
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', 
}

После чего добавляем в наш главный файл urls.py следующее:

urlpatterns = [     
    # ВАШИ URL-АДРЕСА     
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='docs'), 

]

По адресу api/schema/ будет генерироваться JSON-схема нашего API, из которой по адресу api/docs/ будет строиться Swagger-UI документация.

После добавления этих настроек по адресу http://127.0.0.1:8000/api/docs/ можно будет увидеть список всех наших эндпоинтов вот в таком формате:

Общий вид сгенерированной Swagger-UI документации.
Общий вид сгенерированной Swagger-UI документации.

Базовая настройка отображения

Теперь поговорим о более гибкой настройке. Возьмем для примера /groups/

Для начала более детально разберём интерфейс. Здесь есть четыре основных блока:

  • описание, в котором может быть описано назначение эндпоинта и даны какие-либо подсказки

  • принимаемые query-параметры

  • пример запроса

  • пример ответа для каждого статус-кода (200, 201, 400, 404 и так далее)

Теперь попробуем изменить описание. Для этого есть три способа.

  1. Использовать декоратор @extend_schema_view и явно указать описание для каждого метода.

  2. Использовать @extend_schema для каждого метода отдельно

  3. Указать описание в doc-string для каждого метода

# первый пример
@extend_schema_view(
    list=extend_schema(
            summary="Получить список постов",
        ),
    update=extend_schema(
        summary="Изменение существующего поста",
    ),
    partial_update=extend_schema(
        description="""Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
        Cras euismod vehicula hendrerit. Integer placerat lobortis purus, molestie 
        finibus nibh gravida sed. Etiam pretium gravida velit, et rutrum nisi posuere at. 
        Proin hendrerit eros et enim placerat, in commodo lorem tristique. Donec hendrerit ultrices 
        nulla, a maximus diam consectetur id. Cras suscipit ligula vitae sem vulputate vulputate. 
        Duis enim turpis, mollis at maximus nec, tempus ac erat. Nullam at eleifend est, non lacinia erat. 
        Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; 
        Nulla congue condimentum arcu, id sodales dolor aliquet nec. Nullam a consequat neque.""",
    ),
    create=extend_schema(
            summary="Создание нового поста",
        ),
)
class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    # второй пример, так же отобразится в описании 
    @extend_schema(summary="Test description of retrieve method")
    def retrieve(self, request, *args, **kwargs):

        # some logic

        return Response(status=status.HTTP_200_OK)

    def destroy(self, request, *args, **kwargs):
        # третий пример через doc-string

        """Test description of destroy method"""

        return Response(status=status.HTTP_200_OK)

Если описание короткое - используем summary, если длинное - используем description. Либо оба, если нужно и короткое и длинное описание. У summary есть большой плюс - он отображается напротив эндпоинта и помогает быстро сориентироваться. Пример:

Отображение описаний в Swagger UI
Отображение описаний в Swagger UI

Теперь можно добавить тег, для группировки эндпоинтов. Если у каждой группы эндпоинтов проставлен тег, это сильно упростит навигацию и поиск нужной информации.

Теги добавляются с помощью @extend_schema над @extend_schema_view. Таким образом все эндпоинты, помеченные одним тегом будут сгруппированы в один блок.

@extend_schema(tags=["Posts"])
@extend_schema_view(
    retrieve=extend_schema(
        summary="Детальная информация о посте",
        ....

Теперь перейдем к описанию запросов и ответов. В аргумент responses нужно передать словарь вида {"код ответа": "сериализатор или объект OpenApiResponse"}

class DummyDetailSerializer(serializers.Serializer):
    status = serializers.IntegerField()


class DummyDetailAndStatusSerializer(serializers.Serializer):
    status = serializers.IntegerField()
    details = serializers.CharField()

@extend_schema(tags=["Posts"])
@extend_schema_view(
    retrieve=extend_schema(
        summary="Детальная информация о посте",
        responses={
            status.HTTP_200_OK: PostSerializer,
            status.HTTP_400_BAD_REQUEST: DummyDetailSerializer,
            status.HTTP_401_UNAUTHORIZED: DummyDetailSerializer,
            status.HTTP_403_FORBIDDEN: DummyDetailAndStatusSerializer,
            status.HTTP_500_INTERNAL_SERVER_ERROR: OpenApiResponse(
                response=None,
                description='Описание 500 ответа'),
        },
    ),

Для описания стандартных ответов я использую заранее созданный DummyDetailSerializer/DummyDetailAndStatusSerializer.

Так будут выглядеть наши ответы:

Пример отображения ответов от сервера в Swagger UI
Пример отображения ответов от сервера в Swagger UI

Теперь перейдем к более детальной настройке входных параметров на примере update. С помощью аргумента parameters можно добавить новые параметры, либо дополнить существующие.

update=extend_schema(
        summary="Изменение существующего поста",
        request=PostSerializer,
        responses={
            status.HTTP_200_OK: PostSerializer,
            status.HTTP_400_BAD_REQUEST: DummyDetailSerializer,
            status.HTTP_401_UNAUTHORIZED: DummyDetailSerializer,
            status.HTTP_403_FORBIDDEN: DummyDetailAndStatusSerializer,
        },
        parameters=[
            OpenApiParameter(
                name='some_new_parameter',
                location=OpenApiParameter.QUERY,
                description='some new parameter for update post',
                required=False,
                type=int
            ),
        ]
    ),

Так это отобразится в интерфейсе:

Пример отображения дополнительных параметров
Пример отображения дополнительных параметров

Ключевой аргумент при создании дополнительного параметра - location. В нашем случае используем OpenApiParameter.QUERY. Это значит, что этот параметр будет передаваться как query параметр в формате ?some_new_parameter=123.

Так же доступны:

  • OpenApiParameter.PATH - доп. параметр в url

  • OpenApiParameter.HEADER - доп. параметр в headers

  • OpenApiParameter.COOKIE - доп. параметр в cookies

Теперь рассмотрим добавление примеров запроса. В аргумент examples мы должны передать список объектов OpenApiExample. Например:

create=extend_schema(
            summary="Создание нового поста",
            request=PostSerializer,
            responses={
                status.HTTP_200_OK: PostSerializer,
                status.HTTP_400_BAD_REQUEST: DummyDetailSerializer,
                status.HTTP_401_UNAUTHORIZED: DummyDetailSerializer,
                status.HTTP_403_FORBIDDEN: DummyDetailAndStatusSerializer,
            },
            examples=[
                OpenApiExample(
                    "Post example",
                    description="Test example for the post",
                    value=
                    {
                        "title": "testuser",
                        "text": "Some text for post",
                        "category": 1,
                        "author": 1,
                    },
                    status_codes=[str(status.HTTP_200_OK)],
                ),
            ],
        ),

Наш пример отобразится в интерфейсе следующим образом:

Отображение примеров в Swagger UI.
Отображение примеров в Swagger UI.

Общие настройки

Теперь осталось добавить общие настройки отображения. Это делается в файле settings.py следующим образом:

SPECTACULAR_SETTINGS = {
    "TITLE": "Post API", # название проекта
    "VERSION": "0.0.1", # версия проекта
    "SERVE_INCLUDE_SCHEMA": False, # исключить эндпоинт /schema
    "SWAGGER_UI_SETTINGS": {
        "filter": True, # включить поиск по тегам
    },
    "COMPONENT_SPLIT_REQUEST": True
}

Заключение

В заключение могу уверенно сказать, что drf-spectacular - это гибкий и полезный инструмент, Хорошая документация API помогает на всех этапах разработки проекта, упрощает тестирование и поддержку кода.

Комментарии (3)