やりたいこと
django の API の Swagger UI を作成する。
ここでは drf-spectacular を使用する。
drf-spectacular
Swagger UI の画面例
インストール
$ pip install drf-spectacular
django のプログラム例
ファイル構成
drf1
├── drf1
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── items
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └ ...
│ ├── models.py
│ ├── serializers.py
│ ├── services.py
│ ├── tests.py
│ └── views.py
└── manage.py
django のアプリケーションの作成
items アプリケーションを作成し、items の API を実装する。
$ python manage.py startapp items
API ロジック (services.py)
items/services.py
from items.models import Item
def create(name):
item = Item(
name=name,
)
item.save()
return item
def list():
items = Item.objects.filter(
is_deleted=False
).order_by("id")
return items
def get_by_id(id):
item = Item.objects.get(
id=id,
is_deleted=False,
)
return item
def get_by_name(name):
item = Item.objects.filter(
name=name,
is_deleted=False,
)
return item
def to_json(item):
data = {
'id': item.id,
'name': item.name,
'is_deleted': item.is_deleted,
}
return data
def to_json_list(items):
data = [to_json(item) for item in items]
return data
モデル (items.py)
items/models.py
from django.db import models
class Item(models.Model):
name = models.CharField(max_length=32)
is_deleted = models.BooleanField(default=False)
API 本体 (views.py)
items/views.py
from django.views.decorators.csrf import csrf_exempt
from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework import serializers
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from items.serializers import (
ItemNameSerializer,
ItemIdSerializer,
)
from items.services import (
create,
list,
get_by_id,
get_by_name,
to_json,
to_json_list,
)
class ApiViewSet(viewsets.GenericViewSet):
def get_serializer_class(self):
if self.action == 'api_create':
return ItemNameSerializer
elif self.action == 'api_get_by_id':
return ItemIdSerializer
elif self.action == 'api_get_by_name':
return ItemNameSerializer
else:
return super().get_serializer_class()
@csrf_exempt
@action(detail=False, methods=['post'])
def api_create(self, request):
content = {
'data': None,
}
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
name = serializer.validated_data.get('name')
item = create(name)
content['data'] = to_json(item)
return Response(content, status=status.HTTP_201_CREATED)
else:
return Response(content, status=status.HTTP_400_BAD_REQUEST)
@csrf_exempt
@action(detail=False, methods=['get'])
def api_list(self, request):
content = {
'data': None,
}
items = list()
content['data'] = to_json_list(items)
return Response(content)
@csrf_exempt
@action(detail=False, methods=['get'])
def api_get_by_id(self, request, id=None):
content = {
'data': None,
}
item = get_by_id(id)
if item:
content['data'] = to_json(item)
return Response(content)
return Response(content)
@csrf_exempt
@extend_schema(
parameters=[OpenApiParameter(name='name', type=str)],
)
@action(detail=False, methods=['get'])
def api_get_by_name(self, request):
content = {
'data': None,
}
serializer = self.get_serializer(data=request.query_params)
if serializer.is_valid(raise_exception=True):
name = serializer.validated_data.get('name')
items = get_by_name(name)
content['data'] = to_json_list(items)
return Response(content)
return Response(content)
URL の設定 (urls.py)
from django.contrib import admin
from django.urls import path
from items.views import ApiViewSet
urlpatterns = [
# path('admin/', admin.site.urls),
path('api/items/', ApiViewSet.as_view({
'post': 'api_create',
'get': 'api_list',
})),
path('api/items/<int:id>/', ApiViewSet.as_view({'get': 'api_get_by_id'})),
path('api/items/find_by_name/', ApiViewSet.as_view({'get': 'api_get_by_name'})),
]
drf-spectacular の設定
drf1/settings.py
settings.py
INSTALLED_APPS = [
...,
# 追加で記述
'rest_framework',
'drf_spectacular',
# items アプリケーション
'items',
]
...
# drf-spectacular
REST_FRAMEWORK = {
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
SPECTACULAR_SETTINGS = {
'TITLE': 'test project APIs',
'DESCRIPTION': 'description',
'SERVE_INCLUDE_SCHEMA': False,
'SWAGGER_UI_SETTINGS': {},
}
drf1/urls.py の変更
drf1/urls.py
# drf-spectacular の import
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularRedocView,
SpectacularSwaggerView,
)
# URLパターン Swagger UI のパスを追加
urlpatterns = [
path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
...
Swagger UI に API のパラメータを認識させる方法
serializer を使うことで Swagger UI に API のパラメータを認識させることができる。
ここでは、serializer として name と id 用の 2 つの serializer を定義している。
items/serializers.py
class ItemNameSerializer(serializers.Serializer):
name = serializers.CharField(help_text='name', max_length=32)
class ItemIdSerializer(serializers.Serializer):
id = serializers.IntegerField(help_text='id')
views.py の get_serializer_class() で各 API でどの serializer を使うかを指定する。
items/views.py
def get_serializer_class(self):
if self.action == 'api_create':
return ItemNameSerializer
elif self.action == 'api_get_by_id':
return ItemIdSerializer
elif self.action == 'api_get_by_name':
return ItemNameSerializer
else:
return super().get_serializer_class()
各 API では get_serializer() を呼び出して serializer を使用する。
- api_create() では POST パラメータから name を取得する。
items/views.py
serializer = self.get_serializer(data=request.data)
- api_get_by_name() ではクエリパラメータから name を取得する
serializer = self.get_serializer(data=request.query_params)
- api_get_by_id() ではパスから id を取得する。
drf1/urls.py
path('api/items/<int:id>/', ApiViewSet.as_view({'get': 'api_get_by_id'})),
サーバ起動
$ python manage.py runserver 0.0.0.0:8000
Swagger UI の表示
drf1/urls.py に 定義した SpectacularSwaggerView のパスにブラウザでアクセスすると、Swagger UI が表示される。
http://{IP address}:8000/api/schema/swagger-ui/


