前回の記事「Django REST frameworkチュートリアル その1」の続きです。
Tutorial 2: Requests and Responses
事前知識の説明
Request objects
REST frameworkはHttpRequest
を拡張したRequest
オブジェクトを提供しています。Request
オブジェクトの主な属性としてrequest.data
が挙げられますが、これはrequest.POST
よりもフレキシブルなパースをしてくれるとのことです。
例えば、request.POST
がフォームのデータしか扱えないのに対し、request.data
は任意のデータを扱うことができます。さらに、request.POST
がPOST
メソッドでしか使えないのに対し、request.data
はPOST
、PUT
、PATCH
メソッドで使うことができます。
Response objects
Request
オブジェクト同様にREST frameworkはResponse
オブジェクトも提供します。return
するときにはこのオブジェクトでくるんでクライアントに返します。
Status codes
REST frameworkはviews.py
の中でステータスコードを単なる数字で表すのではなく(status=400
など)HTTP_400_BAD_REQUEST
のようにより明確な表し方をします。
Wrapping API views
REST frameworkはAPI viewを記述するための2つのラッパーを用意しています。
- Function based viewで使う
@api_view
デコレータ - Class based viewで使う
APIView
クラス
これらのラッパーは上記のRequestオブジェクトやResponseオブジェクトを使えるよう、よしなにしてくれる機能を提供してくれます。
views.py (Function based view)
それではviews.py
を書き換えてみましょう。前回の記事の続きになります。
## 新しく追加
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
## これらはもう必要ない
# from django.http import HttpResponse, JsonResponse
# from django.views.decorators.csrf import csrf_exempt
# from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
## @api_view()デコレータをつける
# @csrf_exempt
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
## JsonResponseをResponseに変更
# return JsonResponse(serializer.data, safe=False)
return Response(serializer.data)
elif request.method == 'POST':
## JSONParserを介さなくても良くなる
# data = JSONParser().parse(request)
# serializer = SnippetSerializer(data=data)
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
## JsonResponseをResponseに変更
# return JsonResponse(serializer.data, status=201)
return Response(serializer.data, status=status.HTTP_201_CREATED)
## JsonResponseをResponseに変更
# return JsonResponse(serializer.errors, status=400)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
## @api_view()デコレータをつける
# @csrf_exempt
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
Retrieve, update or delete a code snippet.
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
## HttpResponseをResponseに変更
# return HttpResponse(status=404)
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
## JsonResponseをResponseに変更
# return JsonResponse(serializer.data)
return Response(serializer.data)
elif request.method == 'PUT':
## JSONParserを介さなくても良くなる
# data = JSONParser().parse(request)
# serializer = SnippetSerializer(snippet, data=data)
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
## JsonResponseをResponseに変更
# return JsonResponse(serializer.data)
return Response(serializer.data)
## JsonResponseをResponseに変更
# return JsonResponse(serializer.errors, status=400)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
snippet.delete()
## HttpResponseをResponseに変更
# return HttpResponse(status=204)
return Response(status=status.HTTP_204_NO_CONTENT)
少しスッキリしましたね。
@api_view()
デコレータをつけることで、request.data
からJSON形式のデータを扱えるようになっています。そしてクライアントにレスポンスを返すのは全てResponse
オブジェクトに任せられるようになりました。ステータスコードも何を表しているのか一目でわかりますね。
urls.py
.json
でアクセスできるようにする
http://example.com/api/items/4.json
のように拡張子をつけてアクセスしたときにも正しくレスポンスを返すような設定の方法を紹介します。
この設定は簡単で、まずsnippets/views.py
の各メソッドにformat
という引数を追加します。
def snippet_list(request, format=None):
...
def snippet_detail(request, pk, format=None):
...
あとはsnippets/urls.py
にformat_suffix_patterns
を追加するだけです。
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)
こうすることで.json
のような拡張子をつけたアクセスが来ても正しくデータを返してくれるようになります。
ここまででfunction based viewの作成は完了です。
テスト
簡単なテストをしてみましょう。
適当なスニペットを登録してみます。
curl -X POST -H 'Content-Type:application/json' -d '{"title":"hello","code":"world"}' http://localhost:8000/snippets/
返ってきたid
を指定してスニペットを取得してみましょう。
curl -X GET http://localhost:8000/snippets/2/
# {"id":2,"title":"hello","code":"world"}
拡張子をつけても同じように取得できるかと思います。
curl -X GET http://localhost:8000/snippets/2.json
# {"id":2,"title":"hello","code":"world"}
以上になります。
チュートリアルの続きはこちらです。