Django REST Framework(DRF)は、DjangoアプリケーションにおけるRESTful APIの開発を行うためのフレームワークです。
APIを構築する際に中心的な役割を果たすのが、ViewとSerializerですが、それぞれの役割を深く理解し、質の高いコーディングを行うことで、堅牢でスケーラブル、メンテナンスしやすいAPIを実現することが可能になります。
Viewとは
Viewはクライアントからのリクエストを適切に処理し、必要なレスポンスを生成する役割を持ちます。
DRFを用いて実装する場合の具体的な役割としては以下になります。
- リクエストの処理: `View` はクライアントからのHTTPリクエストを受け取り、それに応じて適切なアクション(GET, POST, PUT, DELETE など)を実行する
- コンテキストの提供: リクエストのコンテキスト(ユーザー情報、セキュリティ、リクエストパラメーターなど)を処理し、ビジネスロジックの実行に必要な情報を提供する
- レスポンスの生成: `View` は適切なHTTPレスポンスを生成し、クライアントに返す。これには、ステータスコード、ヘッダー、レスポンスボディ(通常はシリアライズされたデータ)が含まれる
上記の通り、DRFを使用する場合、View内でモデルの作成や更新は行いません。この役割はSerializerが担うことになります。その理由としては以下の通りです。
- 再利用性の向上: ビジネスロジックを `Serializer` に置くことで、異なるビュー間で簡単に共有できる
- 関心の分離: `View` 内にはリクエストとレスポンスに関連するロジックのみ記述することで、データのバリデーションや変換処理を分離できる
- 保守性の向上: ビジネスロジックが一箇所に集中することで、将来の変更やメンテナンスが容易になる
Serializerとは
ただし、Djangoでアプリを作成する際にserializers.pyはデフォルトで含まれないため、手動でファイルを作成することになります。
Serialzerの具体的な役割としては以下になります。
- データの変換: `Serializer` は、複雑なデータタイプ(通常はクエリセットやモデルインスタンス)をJSONに変換し、JSONデータを複雑なタイプに戻すプロセス(シリアライゼーション/デシリアライゼーション)を担当する
- バリデーション: 受け取ったデータが正しい形式であるかどうかを検証する。これには、データタイプのチェック、フィールドレベルのバリデーション、オブジェクトレベルのバリデーションが含まれる
- モデルの保存と更新: `Serializer` は、バリデーションを通過したデータを使用してモデルのインスタンスを作成または更新する責任を担う。このプロセスは、`create` と `update` メソッドをオーバーライドすることでカスタマイズできる
実装例
例えば、以下のようにPostモデルを定義します。
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
次に Post モデルのための Serializer を定義します。
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'content']
最後に、Post モデルに対する API のエンドポイントを提供するための View を作成します。DRF の APIView を使用して、HTTP リクエストの処理、コンテキストの提供、レスポンスの生成を行います。
以下の例では、post リクエストの際に serializer のバリデーションチェックを行い、チェックが通ったときにデータベースに内容を保存します。
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Post
from .serializers import PostSerializer
class PostList(APIView):
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response(serializer.data)
def post(self, request):
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
悪い実装例
以下は view 内で直接モデルにアクセスしてデータベースに保存を行う例です。
バリデーションが行われていないため、不正なデータが保存される可能性があります。また、Serializer を使うことで得られる機能(例えば、データの自動変換、バリデーション、シグナルの利用)が無視されています。
つまり、レスポンスにjson形式で結果を記述する必要があり、コードが冗長になります。
from django.http import JsonResponse
from rest_framework.views import APIView
from .models import Post
class PostCreateBadExample(APIView):
def post(self, request):
title = request.data.get('title')
content = request.data.get('content')
if not title or not content:
return JsonResponse({'error': 'Title and content are required.'}, status=400)
post = Post.objects.create(title=title, content=content)
return JsonResponse({'id': post.id, 'title': post.title, 'content': post.content}, status=201)
まとめ
ViewとSerializerの違いを明確に理解し、品質の高いコーディングを行うための簡単な例を示しました。
コーディングには一つの正解があるわけではありませんが、ベストプラクティスの存在は無視できません。
そのため、最適な選択肢を判断できるような能力を養うことが非常に重要です。