Django REST Framework (DRF)のAPIView・api_viewを使う/python・django
目次
Django REST Framework (DRF)
Django REST Framework (DRF)はDjangoでWeb-APIを開発するフレームワークです。
RESTの意味
DRFの「REST」は「REpresentational State Transfer」の略です。
HTTPメソッドでアクセスしてデータの送受信を行うのを、RESTなWebサービスと呼びます。
RESTの設計原則がRESTfulです。
おおよそ、以下の4つの原則に従うのをRESTful なWebサービスと呼びます。
もう少し詳しい話は、このあたりの記事がわかりやすいと思ったので、リンク貼っておきます。
DRFとDjangoの違い
Djangoは「HTTPResponse」を返し、DRFは「Response」を返します。
Djangoは「HTML」を返し、DRFでは「JSON等」を返します。
Viewも違います。
DRFのViewは以下の観点で大きく2つにわかれます。
- 特定のモデル(DB・クエリセット)に紐づくView
- 特定のモデル(DB・クエリセット)に紐づかないView
です。
特定のモデル(DB・クエリセット)に紐づくビュー
Generic viewとViewSetsです。
作成, 一覧, 取得, 削除, 更新 などのお作法に従って使う場合、可能な限り簡略化して書けるようになっています。
DjangoのFormのAPI版みたいなクラスでと関連づけるだけで、処理を書かなくても、ちゃんと機能するAPIが書けたりする、とても「FrameWork」っぽいViewです。
Generic viewはやりたい処理に対応する多数のクラスの総称みたいな感じです。
ViewSetsは、 取得, 一覧, 登録, 更新, 削除 などのCRUD操作をまとめて扱えるViewです。
ModelViewSetsを継承すると、GenericViewと同様にSerializer を定義するだけで、 取得, 一覧, 登録, 更新, 削除ができるAPIが書けるので、間違いなく便利ですね。
それに、ネットでDRFの情報を探すと、大体ViewSetsを使う例がでてくるので、サンプルにもこまらないのかなと思います。
Generic view
ViewSets
特定のモデル(DB・クエリセット)に紐づかないビュー
GenericViewもViewSetsも便利ですけど、DBを使わない場合には使えません。
そういう場合は「APIView」か「api_view」を使います。
APIViewが「クラスベースのView」
api_viewが「関数型のView」です。
今回とりあげるのは、こちらです。
この両方を使って同じ処理を書いて、比較もしてみます。
サンプルでWebAPIプロキシを作成する
プロキシは英語で「proxy」と書きます。
日本語だと「代理」「中継」みたいな意味です。
WebAPIプロキシは文字通り、既存のWeb-APIを呼び出して結果を中継して返します。
関数型ビューでの実装サンプル
まずは、ソースコードです。
rest/views.py
import requests from rest_framework.decorators import api_view from rest_framework.response import Response @api_view(['GET', 'POST']) def get_address_from_zip(request): zipcode = request.GET.get(key="zipcode", default="1000011") resp = requests.get( 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=' + str(zipcode) + '&limit=1') return Response(resp.json(), status=resp.status_code)
補足します。
@api_view(['GET', 'POST'])
がついて、Responseで返している以外は、普通のメソッドです。
間違いやすいとしたら、
Response(resp.json())
ではなくて
Response(resp.json(), status=resp.status_code)
のように、statusを引き継ぐように書いている部分だと思います。
前者でも何となく動くんですけど、元のAPIのStatusが隠れてしまったりするので後者の方がいいみたいです。
クラスベースのViewでの実装サンプル
今回は「 AddressFromZip」クラスを「addressFromZip.py」として作ります。
まずは、ソースコードから。
rest/address_from_zip.py
import requests from rest_framework.views import APIView from rest_framework.response import Response class AddressFromZip(APIView): def get(self, request): zipcode = request.GET.get(key="zipcode", default="1000011") resp = requests.get( 'http://zipcloud.ibsnet.co.jp/api/search?zipcode=' + str(zipcode) + '&limit=1') return Response(resp.json(), status=resp.status_code)
補足します。
クラスベースのViewは「APIView」を継承して、メソッドの「get」「post」をオーバーライドする形になります。
上記例では、getだけオーバーライドしてますけど、getとpostの両方をオーバーライドしてもかまいません。
この名前を任意のものに変えると、動きません。
要注意です。
WebApiのURLネーミング規則
WebApiプロキシといっても、一応利用する側から見たらAPIですから、URLのネーミングについては、一般的な規則にそってつけることにします。
この辺が参考になります。
urls.pyでパスを設定し実行する
ソースです。
rest/urls.py
from django.contrib import admin from django.urls import path from . import views from . import adress_from_zip as zip urlpatterns = [ path( 'admin/', admin.site.urls), path( 'api/v1/addresses/zip/get', zip.AddressFromZip.as_view(), name='cls-v'), path( 'api/v1/addresses/zip', views.get_address_from_zip, name='fnc-v'), ]
補足します。
URLの構成は、「api/v1/addresses/zip」を基本にしています。
「v1」がバーション。
「addresses」は取得するのが住所(アドレス)なので、その複数形。
「zip」はzipコードから取得するという意味。
原則、名詞しか使わないという基準に基づいて決めてます。
クラスベースの場合の指定サンプル
以下のように指定してます。
'api/v1/addresses/zip/get',
adressFromZip.AddressFromZip.as_view(),
name='cls-v'),
クラスベースの場合、get・postのオーバーライドした方をURLの最後につけて、クラス名.as_view() で定義します。
as_view()によって、URLのgetにマッピングされる・・という仕組みたいですね。
関数ベースの場合の指定サンプル
以下のように指定しています。
'api/v1/addresses/zip',
views.getAddressFromZip,
name='fnc-v'),
Djangoの普通のViewの指定に似ています。
関数名を渡して、任意のURLとマッピングしているだけですから。
実行イメージ
プロジェクトフォルダをカレントフォルダにして、djangoをインストールした仮想環境をactiveにします。
それでお馴染み「python manage.py runserver」します。
郵便番号はパラメータで渡すので、こんな感じ。
ちなみに郵便番号は「1000013」にしてみました。
クラスベースの場合
http://localhost:8000/api/v1/addresses/zip/get?zipcode=1000013
関数ベースの場合
URLをたたいてみると
ちゃんと、とれてます。
今回は、こんなところで・・。
ではでは。