課題
「業務で使っているけど、よく知らない。けどとりあえず動いている」ということが非常に多いので、調べたこと、試したことをまとめていこうと思います。
今回はDjango REST framework編です。
そもそもRESTとは
参考:https://qiita.com/masato44gm/items/dffb8281536ad321fb08
Representation State Transferの略。
特徴としては
- ステートレス(同じリクエストに対して同じ結果を返す)
- リクエストメソッドの種類とCRUDが紐づいている(GET→READ、POST→CREATE、PUT→UPDATE、DELETE→DELETE)
- URLとメソッドの種類で、リソースに対する操作を表現する
- メソッド:GET URL:/users → ユーザー全取得
- メソッド:GET URL:/users/1 → ユーザー1を取得 etc...
他にも色々あるけれども、このルールに則っているAPIを「RESTFulなAPI」と呼びます。
一番の特徴は「メソッドとURLでリソースを操作する」ことだと思います。
メリット・デメリット
参考
- http://kageura.hatenadiary.jp/entry/2018/01/11/なぜポストREST_APIが求められるのか?_REST_APIがカバーでき
- https://qiita.com/mserizawa/items/b833e407d89abd21ee72
メリットとしては、
- URL、APIのルールがわかりやすい
- 開発側も一貫したルールに基づいて開発しやすい
- APIを使用する側も使い方がわかりやすい
デメリットとしては
- 複雑な処理の実装が煩雑
- どうしてもRESTの考え方に合わない部分も出てくる
あくまでRESTは設計原則なので、原則に合わない部分をどうするか、という点で問題でしょうか。
DRFについて
Django REST Framework(以下DRF)は、Django上でRESTFulなAPIを作成するためのフレームワークです。
ざっくりとした使用法としては、
- Modelを定義
- Model:DBに登録するデータクラス。
- ModelのSerializerを定義
- Serializer:実際のデータとModelの橋渡しをするクラス。Model ⇆ Serializer ⇆ DBやデータ みたいなイメージ。
- Viewを定義
- View:リクエストに対してどのようなレスポンスを返すかを定義したもの。DRFではAPIViewやViewSetというクラスにメソッド別の動作を定義する。
- URLを設定
- 指定されたURLとViewを結びつける。
といった流れになります。DRF側で用意されているものを利用すれば、シンプルなAPIなら手軽に作成することができます。
実験
簡単なModelを定義して、CRUD処理を確認します
プロジェクト作成
django-admin startproject sample
アプリ作成
python manage.py startapp drf_sample
設定編集
# 追加分のみ
INSTALLED_APP = [
'drf_sample',
'rest_framework'
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
# テスト用に認証なしで操作できるように設定
'rest_framework.permissions.AllowAny'
]
}
Modelの定義
djangoのデフォルトUserクラスはありますが、今回は実験のため、
first_name,last_name,emailというフィールドを持つUserModelを定義します。
from django.db import models
class User(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
Serializerの定義
drf_sample配下にserializers.pyを作成します
from drf_sample.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
viewの追加
from rest_framework import viewsets
from drf_sample.models import User
from drf_sample.serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
URLの追加
drf_sample配下にurls.pyを作成します
from rest_framework import routers
from drf_sample.views import UserViewSet
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = router.urls
Migrate
python manage.py makemigrations drf_sample
python manage.py migrate
これで完了です。サーバーを起動します。
python manage.py runserver
curlコマンドでCRUD処理を確認します。
GET
curl http://localhost:8000/api/users/
[]
usersで全ユーザーを取得しましたが、まだユーザーがないので空のリストが返ってきました。
では、ユーザーを登録しましょう。
POST
curl -X POST http://localhost:8000/api/users/ -d "first_name=first&last_name=last&email=drf_sample@gmail.com"
{"id":1,"first_name":"first","last_name":"last","email":"drf_sample@gmail.com"}
登録が成功するとそのユーザーのデータが返ってきます。
改めてGETします。
curl http://localhost:8000/api/users/
[{"id":1,"first_name":"first","last_name":"last","email":"drf_sample@gmail.com"}]
先ほど登録したユーザーがリストで返ってきます。
一件取得は
curl http://localhost:8000/api/users/1/
{"id":1,"first_name":"first","last_name":"last","email":"drf_sample@gmail.com"}
これでGET(READ)、POST(CREATE)が確認できました。
PUT
curl -X PUT http://localhost:8000/api/users/1/ -d "first_name=change_first_name&last_name=last&email=drf_sample@gmail.com"
{"id":1,"first_name":"change_first_name","last_name":"last","email":"drf_sample@gmail.com"}
DELETE
curl -X DELETE http://localhost:8000/api/users/1/
確認
curl http://localhost:8000/api/users/
[]
これでCRUD処理は全て確認できました。
参考:http://www.django-rest-framework.org
もっと詳しく
前章のコードをもう少し詳しく見てみます。
Model
ModelクラスはDBのテーブルに対応し、各カラムが各フィールドに対応します。
それぞれの属性にふさわしいフィールドでModelを作成することで、APIを自動生成してくれます。
データのチェックも行ってくれるので、例えばemailフィールドに有効でないメールアドレスを渡すとエラーになったりします。(https://docs.djangoproject.com/ja/2.1/ref/validators/#django.core.validators.EmailValidator)
フィールド一覧:https://docs.djangoproject.com/ja/2.1/ref/models/fields/#model-field-types
Serializer
Serializerの役目は、データとModelの変換です。
- Modelのフィールドに対するserializerを定義する
- create(Modelインスタンスの作成),update(Modelインスタンスの更新)等のメソッド,data(ModelをPythonの標準の形にしたもの)等のプロパティが準備されている
などの特徴があります。
必要に応じて各メソッドをオーバーライドしたり、オプションを追加します。
参考:https://www.django-rest-framework.org/api-guide/serializers/
ViewSet
クラスベースのViewです。URLで呼び出されるメソッドを定義します。
(viewは関数でも良いのですが、クラスベースだと再利用しやすいため推奨されているようです)
今回使用したModelViewSetには、デフォルトで以下のメソッドが用意されています。
- list(全件取得)
- retrive(一件取得)
- create(新規作成)
- update(更新)
- partial_update(部分更新)
- destroy(削除)
参考:https://www.django-rest-framework.org/api-guide/viewsets/
Router
ViewSetで定義したメソッドと、リクエストメソッドとURLを対応付けます。
デフォルトだと以下の対応になります。
リクエストメソッド | URL | 呼び出されるViewSetのメソッド |
---|---|---|
GET | /users/ | list |
GET | /users/{id}/ | retrieve |
POST | /users/ | create |
PUT | /users/{id}/ | update |
PATCH | /users/{id}/ | partial_update |
DELETE | /users/{id}/ | destroy |
新たなURLを追加したい場合は、ViewSetにメソッドを定義→actionデコレータでリクエストメソッドを指定してやれば、そのメソッド名でURLに追加されます。
参考:https://www.django-rest-framework.org/api-guide/routers/
まとめ
DRFを使用することで、RESTfulなAPIを簡単に開発することができます。
思った以上に便利な機能や設定等があり、うまく利用できればコーディング量を大幅に削減できます。
ただ、より複雑な場合はどのように設計・開発すべきかのベストプラクティスはまだまだ見えていないので、経験を積んで行きたいですね。
全く別件なのですが、先日現場で使えるDjangoの教科書を購入しました。まだ読了はしていないのですが、何と無く使っていた部分が簡潔に説明されており、納得しながら読み進められています。おすすめです。