自動化無しに生活無し

WEBとかAIとかLinux関係をひたすら書く備忘録系ブログ

Django Rest Frameworkにて、APIを提供する

thumbnail

Serializerクラスのオブジェクトを返却することで、簡単にAPIを提供することができる。

また、投稿されたデータのバリデーションもSerializerを使えば良いのでとても楽。Ajaxも処理してくれるので、HTMLのフォームを提供するフォームクラスが不要であれば、Serializerに変換しても問題はない。

DRFのシリアライザを使用してAPIを作る

40分簡易掲示板にDELETE、PUTメソッドを追加し、読み書き編集削除の機能を1つのビューで再現させる。

ビュー

from rest_framework.views import APIView
#from django.views import View

#APIで使うレスポンスオブジェクトとステータスコード
from rest_framework.response import Response
from rest_framework import status


from django.shortcuts import render

from django.http.response import JsonResponse
from django.template.loader import render_to_string

from .models import Topic
from .serializer import TopicSerializer


#省略


#上記IndexViewをAPI対応にしたApiIndexViewを作る。
class ApiIndexView(APIView):

    def get(self, request, *args, **kwargs):

        #トピックの一覧を全て返却する。ただし、形式はJsonとステータスコードをセットで返却する。
        topics      = Topic.objects.all()

        #TopicSerializerを経由して、JSON形式に変換。モデルオブジェクト複数であればmany=Trueも指定する。
        serializer  = TopicSerializer(instance=topics, many=True)

        #ステータスコードは下記URLから選ぶ
        #https://www.django-rest-framework.org/api-guide/status-codes/
        
        #シリアライズされたデータ(JSON)とステータスコードを同時に返却する
        return Response(serializer.data, status.HTTP_200_OK)


    def post(self, request, *args, **kwargs):
        print("POST")

        serializer      = TopicSerializer(data=request.data)

        if serializer.is_valid():
            print("バリデーションOK")
            serializer.save()
            #JSONとステータスコードを同時に返却する
            return Response(serializer.data, status.HTTP_201_CREATED)
        else:
            print("バリデーションNG")
            #バリデーションNGなら、この時点でレスポンスを返却する
            return Response(request.data, status.HTTP_400_BAD_REQUEST)

    def delete(self, request, *args, **kwargs):

        topic   = Topic.objects.filter(id=kwargs["pk"]).first()

        if topic:
            print("削除")
            topic.delete()
            return Response(status.HTTP_204_NO_CONTENT)
        else:
            return Response(status.HTTP_404_NOT_FOUND)

api_index   = ApiIndexView.as_view()



"""
下記を実行してみる。DELETE以外はボディとステータスコードが返却される。
curl -X GET "http://localhost:8000/api/index/" -w " %{http_code}\n"
curl -X POST -d "comment=テスト" "http://localhost:8000/api/index/" -w " %{http_code}\n"
curl -X DELETE "http://localhost:8000/api/index/1/" -w " %{http_code}\n"
"""

config/urls.py

from django.contrib import admin
from django.urls import path,include

from bbs import views as bbs_views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("bbs.urls")),

    #CAUTION:DRFではURLの冒頭をapiにしなければAPIとして提供されない。出来ればこの指定はconfigのurls.pyに書くべき
    path('api/index/', bbs_views.api_index, name="api_index"),
    path('api/index/<pk>/', bbs_views.api_index, name="api_index"),

]

Serializerと標準モジュールのjson、JsonResponseはどう違う?

Serializerはバリデーションができる。受け取ったデータの型が異なっていたとしても適切な型に変換した上でバリデーションOKを出す。

更に、Serializerはdata属性にjsonのデータが格納されている。それをそのままレスポンスとして返却することで、jsonのレスポンスが実現できる。Responseではステータスコードの指定もできるので、受け取りしたAPI側はこのステータスコードを元に処理を分岐できる。

認証はどうする?

DjangoRESTFramework単体では、Djangoがデフォルトで装備しているCookie認証(管理サイトにアクセスする際に使用している認証方式と同等)が限界である。

故に、認証時にはCSRFトークンもセットにして、認証のメソッドであるPOSTメソッドのリクエストを送信しなければならない。もし、トークンを使用した認証を行うのであれば、別途djoserというライブラリが必要になる。もしくは自前で作るしかない。

ちなみに、Cookie認証であれば、ビュークラスはLoginRequiredMixinを多重継承することで認証状態をチェックできる。ログイン完了後、以降のセッションをキープさせ、リクエストを送信し続ければ良い。

ソースコード

https://github.com/seiya0723/startup_bbs_restful_api

参照元

スポンサーリンク

シェアボタン

Twitter LINEで送る Facebook はてなブログ