1.はじめに
今回は、pythonの「Django」というWebアプリケーションフレームワークを使用し、REST APIを作成します。
作成するREST APIは、これから作るであろう、Nuxt.jsからアクセスする際に使用するつもりです。
REST APIをなるべく簡単に作成することが目的です。Djangoそのものにはあまり深入りしません。
1.1 Django REST Frameworkとは
APIは、Djangoの[Django REST Framework]を使用します。
Django、及びDjango REST Frameworkを仕事で使用している関係で、少しだけ理解しているので、時間短縮のために使用しました。
ただし、他のライブラリと比較すると少し自由度が低いと思います。「型」として覚えてしまえばいいのかもしれません。
1.2 ソースコードについて
ここに今回実装した、ソースコード一式格納してあります。
2.環境設定
2.1 python環境設定
以下のように環境設定します。
$ mkdir addr_api ; cd addr_api $ export PIPENV_VENV_IN_PROJECT=true $ pipenv install django djangorestframework django-cors-headers django-filter
バージョンは以下の通りです。
- Django==2.2.4
- djangorestframework==3.10.2
2.2 Django REST Framework設定
ここでは、table_rest_apiというプロジェクトの中に、tableappというREST APIアプリケーションを作成します。
$ pipenv run django-admin startproject table_rest_api $ cd table_rest_api $ pipenv run django-admin startapp tableapp
この時点で以下のディレクトリ構成になっています。
./ manage.py table_rest_api/ __init__.py settings.py urls.py wsgi.py tableapp/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
2.3 settings.py
settings.pyに以下を追加します。
主にAPI用に追加していますが、LANGUAGE_CODEとTIME_ZONEは、admin画面(後述)用に追加しています。
table_rest_api/settings.py
ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ ...(略) 'tableapp', 'rest_framework', ] ## (中略) LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo'
3.REST API作成
以下のようにREST APIを作成していきます。
3.1 モデル定義
モデルを定義します。nuxt.jsのサンプルが住所録的なものなので、Addrsとして定義しました。
見た通りですが、jobsの所だけ妥協しました。本来なら配列を使用するところです。少々面倒なので、今回は文字列にしています。
tableapp/models.py
from django.db import models class Addr(models.Model): GENDER_MAN = "男性" GENDER_WOMAN = "女性" GENDER_OTHER = "その他" GENDER_SET = ( (0, GENDER_MAN), (1, GENDER_WOMAN), (2, GENDER_OTHER), ) name = models.CharField(max_length=128) birthday = models.DateField() gender = models.IntegerField(choices=GENDER_SET) address = models.CharField(max_length=128) jobs = models.CharField(max_length=1024) note = models.CharField(max_length=128) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
3.2 データベース構築
データベース情報を設定します。test_rest_api/settings.pyに既に設定されていますが、
ここでは、SQLite3を使用します。
$ pipenv run python manage.py makemigrations $ pipenv run python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, tableapp Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying sessions.0001_initial... OK Applying tableapp.0001_initial... OK
3.3 admin画面の作成
admin画面を作成します。APIには直接関係ないですが、設定しておくと画面からデータを設定できます。
以下は、管理者ユーザの作成です。
$ pipenv run python manage.py createsuperuser Username (leave blank to use 'tanino'): Email address: tanino@a2.mbn.or.jp Password: Password (again): Superuser created successfully.
モデルを管理画面から変更できるようにしておきます。
tableapp/admin.py
from django.contrib import admin from .models import Addr @admin.register(Addr) class AddrAdmin(admin.ModelAdmin): pass
以下で起動します。
$ pipenv run python manage.py runserver 0.0.0.0:18899
以下でadmin画面にアクセスできます。
http://192.168.132.129:18899/admin
ログイン画面が以下です。
ログインすると以下の画面になります。
データを追加しておきます。
4. Django REST Framework追加
Django REST Frameworkを追加していきます。
4.1 Serializers追加
Serializersとは、データ入出力時に使用する、モデルへの橋渡しをするクラスです。Formクラスと似ています。
ここでは、AddrSerializersを追加します。Addrモデルとの橋渡しです。fieldsには、APIとして返却したいカラムを列挙します。
tableapp/serializers.py
# coding: utf-8 from rest_framework import serializers from .models import Addr class AddrSerializer(serializers.ModelSerializer): class Meta: model = Addr fields = ('id', 'name', 'birthday', 'gender', 'address', 'jobs', 'note', 'created_at', 'updated_at')
4.2 ViewSet追加
ViewSetとは、APIのView(通常で言うところのコントローラ)を抽象化したクラスです。自動的に、createや、destroyを定義してくれます。
以下の設定はModels.pyに依存する場合の記述方法です。モデルに依存しない場合は、viewsets.ViewSetを使用できます。
ここでは、APIを定義することを優先するので、簡略化して記述します。
tableapp/views.py
# coding: utf-8 import django_filters from rest_framework import viewsets, filters from .models import Addr from .serializer import AddrSerializer class AddrViewSet(viewsets.ModelViewSet): queryset = Addr.objects.all() serializer_class = AddrSerializer
4.3 Urlpatterm追加
URL設定を追加します。
以下はREST APIのURLを設定します。
tableapp/urls.py
# coding: utf-8 from rest_framework import routers from .views import AddrViewSet router = routers.DefaultRouter() router.register(r'addrs', AddrViewSet)
以下は、全体的なプロジェクト側のURL設定です。「#追加部分」を追加します。
table_rest_api/urls.py
from django.contrib import admin from django.urls import path from django.urls import include # 追加 from tableapp.urls import router as tableapp_router # 追加 urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(tableapp_router.urls)), # 追加 ]
以下で起動します。
$ pipenv run python manage.py runserver 0.0.0.0:18899
4.4 CORS追加
CORSとは、Cross-Origin Resource Sharingの略です。Webブラウザから別ドメインにアクセスするのを可能にする仕組みです。
通常、HTML(を含むJavaScript)内からダウンロードサイトからしかアクセスできないよう、
Webブラウザが実装していますが、CORSの仕組みを使うと別ドメインへアクセスできます。
つまり、CORSの設定は、JavaScriptが別ドメインにアクセスしなければ基本的に不要です。
設定方法は以下の通りです。
table_rest_api/settings.py
INSTALLED_APPS = [ ...(略) 'corsheaders', ] MIDDLEWARE = [ ...(略) 'corsheaders.middleware.CorsMiddleware', ] CORS_ORIGIN_ALLOW_ALL=True
4.5 APIアクセス
以下でAPIコンソールにアクセスできます。
http://192.168.132.129:18899/api
http://192.168.132.129:18899/api/addrs
にブラウザからアクセスすると、以下のような画面を表示します。
curlすると通常のJSONが取得できます。
$ curl http://192.168.132.129:18899/api/addrs [{"id":1,"name":"tanino","birthday":"2019-08-16","gender":0,"address":"ここではないどこか","jobs":"なし","note":"てすと","created_at":"2019-08-16T12:43:52.331031+09:00","updated_at":"2019-08-16T12:43:52.331050+09:00"}]
4.6 ディレクトリ構成
ディレクトリ構造は以下の通りです。
table_rest_api/ |--db.sqlite3 |--manage.py |--table_rest_api | |--__init__.py | |--settings.py | |--urls.py | |--wsgi.py |--tableapp | |--__init__.py | |--admin.py | |--apps.py | |--migrations | | |--0001_initial.py | | |--__init__.py | |--models.py | |--serializer.py | |--tests.py | |--urls.py | |--views.py
5. OpenAPIでAPI仕様書の自動生成
ちょっと前は、SwaggerといわれていたAPI定義方法です。見栄えもよいので、設定しておこうと思います。
5.1 スキーマ
スキーマは以下のように生成します。といっても、実際にはスキーマを出力しても使うところがありません。
$ pipenv install uritemplate pyyaml $ pipenv run python manage.py generateschema --format openapi > schema.yml
以下のようなschema.ymlが自動生成されます。
openapi: 3.0.2 info: title: '' version: TODO paths: /api/addrs: get: operationId: ListAddrs parameters: [] responses: '200': content: application/json: schema: required: - name - birthday - gender - address - jobs ....
5.2 API定義表示(swagger-ui)
swaggerのAPI定義が表示できるように設定しておきます。
プロジェクト側(table_rest_api側)のurls.pyに以下を追加しておきます。
API側のURL設定にしなくても動作するようです。
table_rest_api/urls.py
from django.views.generic import TemplateView from rest_framework.schemas import get_schema_view from rest_framework.renderers import JSONOpenAPIRenderer schema_view = get_schema_view(title='Addresses API', url='https://192.168.132.129/api/', renderer_classes=[JSONOpenAPIRenderer] ) path('openapi/', get_schema_view(title="Addresses", description="Addresses API", ), name='openapi-schema'), path('swagger-ui/', TemplateView.as_view(template_name='swagger-ui.html', extra_context={'schema_url':'openapi-schema'} ), name='swagger-ui'),
あとはtemplates/swagger-ui.htmlを設定しました。以下は参考文献の通りにしただけです。
<!DOCTYPE html> <html> <head> <title>Swagger</title> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="//unpkg.com/swagger-ui-dist@3/swagger-ui.css" /> </head> <body> <div id="swagger-ui"></div> <script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script> <script> const ui = SwaggerUIBundle({ url: "{% url schema_url %}", dom_id: '#swagger-ui', presets: [ SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset ], layout: "BaseLayout" }) </script> </body> </html>
以下にアクセスすると、API定義が出てきます。さほど設定していないのに出力出来て便利です。
http://192.168.132.129:18899/swagger-ui/
6.おわりに
ここではAPIの設定だけ行いました。
次はAPIを使用したnuxt.jsのサンプルを作成したいと思います。
7.参考
- Django REST Frameworkの参考
https://qiita.com/kimihiro_n/items/86e0a9e619720e57ecd8
https://qiita.com/Morinikiz/items/c2af4ffa180856d1bf30 - OpenAPI仕様
https://www.django-rest-framework.org/topics/documenting-your-api/ - OpenAPI サンプル
https://github.com/matthewhegarty/rest-framework-tutorial/tree/swagger-ui