RESTfull API
-
RESTfull APIの4つの原則
- URIで公開されている
- HTTPメソッドによりリクエストを受け付けるインターフェースを持つ
- ステートレスな処理実行
- 処理の結果をHTTPステータスコードに変換して応答する
Django Rest Framework(DRF)
DjangoでRestAPIを作成できるフレームワークとして,Django Rest Framework(DRF)があります。
端折っていますが,下の3つのファイルが重要です。
- models.py
データモデルを定義するファイル。ユーザーから提供されたデータをDBに格納したり,DBのテーブルに対して直接クエリを行うような処理を実装する - views.py
HTTPメソッド(GET、POST、PUT、DELETEなど)に基づいて,modelsに対して問い合わせを行う - serializers.py:
データのバリデーションや変換(json形式)などを行う
ユーザーから見ると,view
→serializer
→model
→DB
の順にアクセスすることになります。
テーブルの操作
適当な題材として,パンのレビューを収集するBread
アプリを作ります。
https://github.com/nm-dl1212/django_restapi
ユーザーが入力する項目は以下の4つとします。
- 名前
- 税抜き価格
- 説明
- 評価(うまい/そこそこ/まずいの3段階)
新規オブジェクトが追加されたタイミングで,以下の3つの項目をテーブルに追加します。
- 新規追加された時間
- 更新された時間
- 税込み価格
ここで, 「税込み価格」は入力値の「税抜き価格」から自動で計算されるようにします。
今回は単純な掛け算ですが,今後,入力値に対して複雑な処理を実行できるようにすることを意図しています。
model
from django.db import models
class Bread(models.Model):
# ユーザーに入力させる項目
name = models.CharField(max_length=30)
price = models.IntegerField()
description = models.CharField(max_length=500)
REVIEW_SET = (
("Good", "うまい"),
("Soso", "そこそこ"),
("Bad", "まずい"),
)
review = models.CharField(choices=REVIEW_SET, max_length=8)
# 自動追加される項目
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# 計算式を追加
@property
def priceWithTax(self):
return int(self.price * 1.1)
def __str__(self):
return self.name
入力の型に合わせて複数のmodels.**Field
クラスが用意されており,ここで入力のバリデーションを行います。
税抜き価格price
に定数を書けて税込み価格priceWithTax
を返却するプロパティを実装します。
view
from rest_framework import viewsets
from .models import Bread
from .serializers import BreadSerializer
class BreadViewSet(viewsets.ModelViewSet):
queryset = Bread.objects.all()
serializer_class = BreadSerializer
BreadViewSet
は,ModelViewSet
クラスを継承しています。
django公式(https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset)にあるように,
ModelViewSet
はデータベースへのCRUD処理のメソッドを持っており,それを継承したBreadViewSet
でも同様の操作が可能になります!
The actions provided by the ModelViewSet class are .list(), .retrieve(), .create(), .update(), .partial_update(), and .destroy().
queryset
では,Modelのどの項目を取得するかを定義しています。ここではBread
のすべてを対象にするので,Bread.objects.all()
とします。
また,ここで次節のSerializerのクラスを指定します。
serializer
from rest_framework import serializers
from .models import Bread
class BreadSerializer(serializers.ModelSerializer):
class Meta:
model = Bread
fields = ['name', 'price', 'description', 'review', 'priceWithTax'] # GET時に渡す項目
read_only_fields = ['created_at', 'updated_at'] # 読み取り専用
serializerはmodelとview間でデータを変換する役割を持ちます。
下記のようにmodelの中ではインスタンスとしてデータを保持しており,これをviewに渡すときにjsonオブジェクトに変換する必要があります。
この時,model→viewへの変換をシリアライズ,view→modelへの変換をデシリアライズと呼びます。
jsonオブジェクトとmodelインスタンス間の仲介をserializerに担当させることで,GETやPOSTなどのリクエストに文字列ベースのインプットを付与することが可能になります。
# modelの中でのデータの扱い
instance = Model(name='John', age=25, sex='male')
# viewの中でのデータの扱い
{
"name": "John Doe",
"age": 25
}
実際にDBにクエリを投げる
まず,以下のようにPOSTを投げてみます。
Bread
モデルなので,パンのレビューを投げてみました。
$ curl -X POST -H "Content-Type: application/json" -d \
'{"name": "あんぱん", "price": 120, "description": "あんこたっぷり", "review": "Good"}' \
http://localhost:8000/bread/bread/
続けて,GETで登録されているオブジェクトを拾ってみます。先ほどの登録したオブジェクトが返ってきますが,priceWithTax
がDjango側で計算され追記されているのがポイントになります。
$ curl -X GET http://localhost:8000/bread/bread/
# [{"name":"あんぱん","price":120,"description":"あんこたっぷり","review":"Good","priceWithTax":132}]
まとめ
Django Rest Frameworkを使って,簡単なDB操作を実行しました。
これから,DBをPostgreSQLに変更してみたり,機械学習のようなもっと複雑なPython処理を実行できるようにブラッシュアップしたいと思います。