OpenAPI/Swagger, drf-spectacular, drf-yasg
Хорошая документация API помогает разработчикам быстро понять, как использовать ваш API. DRF поддерживает автоматическую генерацию OpenAPI/Swagger документации.
OpenAPI (ранее Swagger) — спецификация для описания REST API. Позволяет:
Современная библиотека для генерации OpenAPI схем:
pip install drf-spectacular# settings.py
INSTALLED_APPS = [
# ...
'drf_spectacular',
]
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
SPECTACULAR_SETTINGS = {
'TITLE': 'My Project API',
'DESCRIPTION': 'API описание проекта',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
'COMPONENT_SPLIT_REQUEST': True,
'TAGS': [
('articles', 'Статьи'),
('users', 'Пользователи'),
('auth', 'Аутентификация'),
],
}# urls.py
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
SpectacularRedocView,
)
urlpatterns = [
# OpenAPI схема (JSON)
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
# Swagger UI (интерактивная документация)
path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'),
name='swagger-ui'),
# ReDoc (альтернативный UI)
path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'),
name='redoc'),
]Доступ:
http://localhost:8000/api/docs/http://localhost:8000/api/redoc/http://localhost:8000/api/schema/from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiResponse
from drf_spectacular.types import OpenApiTypes
from rest_framework import viewsets
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@extend_schema(
summary='Список статей',
description='Возвращает пагинированный список всех статей',
tags=['articles'],
parameters=[
OpenApiParameter(
name='search',
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
description='Поиск по названию и содержанию',
required=False,
),
OpenApiParameter(
name='ordering',
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
description='Поле для сортировки (префикс - для убывания)',
required=False,
),
],
responses={
200: ArticleSerializer(many=True),
401: OpenApiResponse(description='Неавторизованный запрос'),
},
)
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
@extend_schema(
summary='Создание статьи',
description='Создаёт новую статью с указанными данными',
tags=['articles'],
request=ArticleCreateSerializer,
responses={
201: ArticleSerializer,
400: OpenApiResponse(description='Ошибка валидации'),
},
)
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
@extend_schema(
summary='Получение статьи',
description='Возвращает статью по ID',
tags=['articles'],
parameters=[
OpenApiParameter(
name='id',
type=OpenApiTypes.INT,
location=OpenApiParameter.PATH,
description='ID статьи',
),
],
)
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)Кастомизация сериализатора в документации:
from drf_spectacular.utils import extend_schema_serializer, OpenApiExample
from drf_spectacular.types import OpenApiTypes
from rest_framework import serializers
@extend_schema_serializer(
examples=[
OpenApiExample(
'Пример статьи',
value={
'id': 1,
'title': 'Моя статья',
'content': 'Текст статьи',
'author': 5,
'created_at': '2024-01-01T12:00:00Z',
},
response_only=True,
)
]
)
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['id', 'title', 'content', 'author', 'created_at']Документирование полей сериализатора:
from drf_spectacular.utils import extend_schema_field
from drf_spectacular.types import OpenApiTypes
from rest_framework import serializers
class ArticleSerializer(serializers.ModelSerializer):
author_name = serializers.SerializerMethodField()
is_published = serializers.SerializerMethodField()
@extend_schema_field(OpenApiTypes.STR)
def get_author_name(self, obj):
return obj.author.username
@extend_schema_field(OpenApiTypes.BOOL)
def get_is_published(self, obj):
return obj.is_published
class Meta:
model = Article
fields = ['id', 'title', 'author_name', 'is_published']# settings.py
SPECTACULAR_SETTINGS = {
'SECURITY': [
{
'bearerAuth': [],
},
],
'COMPONENTS': {
'securitySchemes': {
'bearerAuth': {
'type': 'http',
'scheme': 'bearer',
'bearerFormat': 'JWT',
'description': 'JWT токен аутентификации',
},
'cookieAuth': {
'type': 'apiKey',
'in': 'cookie',
'name': 'sessionid',
'description': 'Session cookie аутентификация',
},
},
},
}Документирование кастомных действий:
from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework.decorators import action
from rest_framework.response import Response
class ArticleViewSet(viewsets.ModelViewSet):
@extend_schema(
summary='Публикация статьи',
description='Публикует статью, делая её видимой для всех',
tags=['articles'],
methods=['POST'],
request=None, # Нет тела запроса
responses={
200: {'type': 'object', 'properties': {'status': {'type': 'string'}}},
403: {'description': 'Нет прав на публикацию'},
},
)
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
article = self.get_object()
if not request.user.is_staff:
return Response(
{'error': 'Только администраторы могут публиковать'},
status=403
)
article.is_published = True
article.save()
return Response({'status': 'published'})
@extend_schema(
summary='Комментарии к статье',
description='Возвращает список комментариев к статье',
tags=['articles', 'comments'],
methods=['GET'],
responses={
200: CommentSerializer(many=True),
},
)
@action(detail=True, methods=['get'])
def comments(self, request, pk=None):
article = self.get_object()
comments = article.comments.all()
serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)Устаревшая, но популярная библиотека:
pip install drf-yasg# settings.py
INSTALLED_APPS = [
# ...
'drf_yasg',
]
# urls.py
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from rest_framework import permissions
schema_view = get_schema_view(
openapi.Info(
title='My Project API',
default_version='v1',
description='API описание',
contact=openapi.Contact(email='contact@example.com'),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui'),
path('redoc/', schema_view.with_ui('redoc', cache_timeout=0),
name='schema-redoc'),
]Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.