概要
この記事は初心者の自分がRESTful なAPIとswiftでiPhone向けのクーポン配信サービスを開発した手順を順番に記事にしています。技術要素を1つずつ調べながら実装したため、とても遠回りな実装となっています。
前回のSwiftのTableViewCellを使ってTableViewを自由にカスタマイズで、データベースで管理するクーポン情報をAPIを通してアプリが取得し、リスト形式で表示するところまで作成しました。
次はこのAPIをRESTfulなAPIに改造します。改造にあたりコードを大幅に変更するため、一旦GETで全てのクーポン情報をレスポンスするだけのAPIを実装し、その後にリクエストに応じたクーポン情報をレスポンスするよう修正を加えていきます。
参考
- Django REST Framework の使い方メモ
- Django REST Frameworkを使って爆速でAPIを実装する
- 【Django入門】REST FrameworkでAPIを作ってみよう
- 適当に作る python Djnago REST frameworkで作る初めてのAPI
- よく使うcurlコマンドのオプション
環境
Mac OS 10.15
VSCode 1.39.2
pipenv 2018.11.26
Python 3.7.4
Django 2.2.6
手順
- Django Rest Framework をインストールする
- Django Rest Framework を取り込む
- Serializerを定義する
- View.pyを改造する
- URL_patternを定義する
- curl コマンドを使って動作確認をする
Django Rest Framework をインストールする
自分はpipenvでpythonのプロジェクト(仮想環境)を作っているので、そこに django rest framework をインストールします。pipenvのシェルに入り、インストールのコマンドを実行します。
$ pipenv shell #シェルに入る
$ pipenv install djangorestframework # インストール実行
インストール完了後にPipfileの中を見ると、[packages]
にdjangorestframework
が追加されています。
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
django = "*"
djangorestframework = "*"
[requires]
python_version = "3.7"
Django Rest Framework を取り込む
プロジェクト名のディレクトリ配下のsetting.py
の INSTALLED_APPS = {
に インストールした rest_framework
を追加するだけです。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'coupon',
'rest_framework', # 追加
]
これで Django Rest Framework を使う準備が完了しました。
Serializerを定義する
Rest Framework を使うには Serializer というモジュールが必要です。アプリのディレクトリ配下に自分で Serializer のファイルを作り実装します。
下記のように実装しました。
from rest_framework import serializers # Django Rest Frameworkをインポート
from .models import Coupon # models.py のcouponクラスをインポート
class CouponSerializer(serializers.ModelSerializer):
class Meta:
model = Coupon # 扱う対象のモデル名を設定する
fields = '__all__'
上のコードで、fields
はレスポンスしたいモデルフィールド(ここではクーポン情報)を指定します。特に指定せず全ての項目をレスポンスする場合は'__all__'
とします。
View.pyを改造する
views.py
を Django Rest Framework を使った場合に合わせて改造します。
- rest_framework の viewsets と filters をインポート
- 上で定義した serializer の CouponSerializer をインポート
- 全てのクーポン情報をレスポンスする queryset に変更
- rest_framework を使うと データをjson 形式にしたり dump したり、HTTPでレスポンスする処理は自動でやってくれるようなので、それらの不要になった処理を削除
- 上で定義した serializer.pyのCouponSerializer を呼ぶ。
コードは下記のようになります。非常にシンプルになりました。
from django.shortcuts import render
from .models import Coupon
from rest_framework import viewsets, filters
from .serializer import CouponSerializer
class CouponViewSet(viewsets.ModelViewSet):
queryset = Coupon.objects.all() # 全てのデータを取得
serializer_class = CouponSerializer
URL_patternを定義する
ami_coupon_api/urls.py
と、coupon/urls.py
を編集します。実感としてはcoupon/urls.py
から編集した方が良さそうです。
coupon/urls.py
の編集内容は下記の通りです。
- rest_framework の routers をインポート
- views.py で定義した、CouponViewSet をインポート
- router を定義して、
router.register
に URLとそのURLがリクエストされた時に呼び出すview.pyのクラス(ここでは CouponViewSet)を紐付ける。
from django.urls import path
from . import views
from rest_framework import routers
from .views import CouponViewSet
router = routers.DefaultRouter()
router.register(r'coupons', CouponViewSet)
上記で、r’coupons’
の ‘coupons’
の部分が リクエストURLの後ろに付きます。
ami_coupon_api/urls.py
の編集内容は下記の通りです。
-
django.conf.urls
の url と include をインポート -
coupon/urls.py
で定義した router を coupon_routerとしてインポート - urlpatternsにURLと呼び出し先を定義
- URLが
admin/
の場合は、django の コンソールへ進むように設定 -
api/
の場合は、router で設定したオブジェクトへ進むように設定
from django.contrib import admin
from django.urls import path,include
from django.conf.urls import url, include
from coupon.urls import router as coupon_router
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(coupon_router.urls)),
]
curl コマンドを使って動作確認をする
新しいターミナルを開いて GET、POST、PUT のリクエストを試してみます。リクエストの書き方は下記の通りです。-X はHTTPメソッド(GET、POST、PUT など)を指定するためのオプションです。なお、GETとPOST は指定しなくても実行可能でした。
$ curl -X [HTTPメソッド] [URL] [リクエストパラメータ]
GETを試します。リクエストパラメータは付けていません。
$ curl -X GET http://127.0.0.1:8000/api/coupons/
こんなjsonが返ってきました。
[{"id":1,"code":"0001","benefit":"お会計から1,000円割引","explanation":"5,000円以上ご利用のお客様限定。他クーポンとの併用不可。","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":2,"code":"0002","benefit":"お会計を10%オフ!","explanation":"他クーポンとの併用不可","store":"有楽町店","start":"2019-10-01","deadline":"2019-12-31","status":true},{"id":3,"code":"0003","benefit":"【ハロウィン限定】仮装して来店すると30%オフ","explanation":"全身の50%以上を仮装されているお客様限定(判断はスタッフの感覚とさせて頂きます)。他クーポンとの併用不可","store":"神田店","start":"2019-10-31","deadline":"2019-10-31","status":true},{"id":4,"code":"0004","benefit":"【9月限定】お月見団子サービス","explanation":"ご希望のお客様に月見団子をプレゼント! 他クーポンとの併用可能です!","store":"全店","start":"2019-09-01","deadline":"2019-09-30","status":true},{"id":5,"code":"0005","benefit":"【雨の日限定】お会計から15%オフ","explanation":"クーポンが配信された時だけ利用可能です。他クーポンとの併用不可","store":"全店","start":"2019-10-01","deadline":"2019-12-31","status":false},{"id":6,"code":"0006","benefit":"【日曜日限定】乾杯テキーラサービス","explanation":"テキーラを人数分サービスします。他クーポンとの併用可。","store":"神田店","start":"2019-11-03","deadline":"2019-12-01","status":true}]
POSTを試します。
curl -X POST http://127.0.0.1:8000/api/coupons/ -d "code=0007" -d "benefit=お会計から19%引き" -d "explanation=12月29日~12月31日限定。 " -d "store=神田店" -d "start=2019-12-29" -d "deadline=2019-12-31" -d "status=true"
上手くいくとPOSTしたデータがjsonで返って来ます。
{"id":7,"code":"0007","benefit":"お会計から19%引き","explanation":"12月29日~12月31日限定。","store":"神田店","start":"2019-12-29","deadline":"2019-12-31","status":true}
PUTを試します。
PUTの時はHTTPメソッドを指定する必要があります。それより重要なのは、URLにテーブルのプライマリキーを指定する必要があります。couponモデルでは”id”がプライマリキーになっているので、URLの末尾に上書きしたいデータのid(ここでは 7 )を指定します。
curl -X PUT http://127.0.0.1:8000/api/coupons/7/ -d "code=0007" -d "benefit=お会計から19%引き" -d "explanation=12月29日~12月31日限定。他のクーポンとの併用不可 " -d "store=神田店" -d "start=2019-12-29" -d "deadline=2019-12-31" -d "status=true"
上手くいくと上書きされたデータがjsonで返って来ます。
{"id":7,"code":"0007","benefit":"お会計から19%引き","explanation":"12月29日~12月31日限定。他のクーポンとの併用不可","store":"神田店","start":"2019-12-29","deadline":"2019-12-31","status":true}
DELETEを試します。
先ほどPOSTしたリクエストをもう一度実行し、id=8のクーポンを作ります。GETリクエストかDjangoサーバのコンソールでid=8のクーポンが追加されたことを確認してください。
次に、下記のリクエストでid=8のクーポンを削除します。PUTと同様に削除対象のクーポンのプライマリキーの指定が必要です。
curl -X DELETE http://127.0.0.1:8000/api/coupons/8/
上手くいくと何も返って来ません。
GETリクエストかDjangoサーバのコンソールでid=8のクーポンが削除されたことを確認してください。
ここまでで基本的なRest Framework が出来ました。ここから 条件に合うクーポンのみをGETするためのフィルタや認証機能を追加していきます。