DjangoでWeb APIであるGraphQLを実装してみます。
本記事ではDjangoにおいてGraphQLサーバを構築するためのGrapheneライブラリーを利用し、単一のエンドポイントを作成します。またそのエンドポイントに対してREST APIのGETメソッドに該当するクエリ(query)を実行し、結果(レスポンス)が返ってくることを確認します。データベースはDjangoに備わっているSQLiteを利用しています。
環境
Mac OS
Django==2.2.6
graphene==2.1.8
Grapheneをインストールします。
1 |
$ pip install graphene-django |
myprojectプロジェクトおよびmyappアプリケーションの作成済みを前提に話を進めていきます。
settings.pyのINSTALLED_APPSの項目にgraphene_djangoを設定します。
myproject/myproject/settings.py
1 2 3 4 5 6 7 8 9 10 |
INSTALLED_APPS = [ 'myapp', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'graphene_django', ] |
さらに下記項目を追記します。
1 2 3 |
GRAPHENE = { 'SCHEMA': 'myproject.schema.schema', } |
モデルの定義
今回は単純に独立した2つのモデルを用意しました。マイグレーションファイルの作成・実行をし、あらかじめ管理サイト等でデータを登録しておいて下さい(手順は関連ページをご覧下さい)。
myproject/myapp/models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from django.db import models class Member(models.Model): name = models.CharField(max_length=100) nickname = models.CharField(max_length=100) age = models.IntegerField() def __str__(self): return self.name class Club(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name |
関連ページ
スキーマの定義
myappディレクトリ内にschema.pyを作成し、下記のように編集します。
myproject/myapp/schema.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import graphene from graphene_django import DjangoObjectType from .models import Member, Club class MemberType(DjangoObjectType): class Meta: model = Member class ClubType(DjangoObjectType): class Meta: model = Club class Query(graphene.ObjectType): members = graphene.List(MemberType) member = graphene.Field(MemberType, id=graphene.Int()) clubs = graphene.List(ClubType) def resolve_members(self, info, **kwargs): return Member.objects.all() def resolve_member(self, info, **kwargs): id = kwargs.get('id') return Member.objects.get(pk=id) def resolve_clubs(self, info, **kwargs): return Club.objects.all() |
DjangoObjectTypeをサブクラス化し、2つのモデルからそれぞれのタイプ(MemberType、ClubType)を作成します。Queryクラスにはmembersおよびmember、そしてclubsをスキーマのフィールドとして記述しています。例えばmembersはすべてのmemberオブジェクト、memberはidを引数とした特定のmemberオブジェクトが格納されます。最後に各フィールドに対応したリゾルバ関数(resolve_フィールド名())を記述することによって、フィールドの値を返すようにします。
myprojectディレクトリ内(ルートディレクトリ直下ではありません)にもschema.pyを作成し、下記のように編集します。
myproject/myproject/schema.py
1 2 3 4 5 6 7 8 9 |
import graphene import myapp.schema class Query(myapp.schema.Query, graphene.ObjectType): pass schema = graphene.Schema(query=Query) |
エンドポイント
最後にurls.pyを編集し、エンドポイントを有効にします。
myproject/myproject/urls.py
1 2 3 4 5 6 7 8 9 |
from django.contrib import admin from django.urls import path from django.views.decorators.csrf import csrf_exempt from graphene_django.views import GraphQLView urlpatterns = [ path('admin/', admin.site.urls), path('graphql/', csrf_exempt(GraphQLView.as_view(graphiql=True))), ] |
8行目
CSRF対策を無効にしています。無効にしないと例えばcurlによってデータを取得できません(後述)。またgraphiql=Trueを設定すると、ブラウザでGraphiQLの画面を表示させることができます(下記画像参照)。
以上で「http://localhost:8000/graphql/」がGraphQLのエンドポイントとなり、クエリを実行することが可能となります。実際にブラウザでGraphiQLの画面を表示して、クエリを実行すると、JSONオブジェクトが返ってくることを確認できます。仮にnameやnicknameを含めずにクエリを実行すると、それらクエリと同じ構造を持つJSONオブジェクトが返ってきます。
クエリの記述。
1 2 3 4 5 6 7 |
query { members { name nickname age } } |
GraphiQL画面
idが2の結果のみを取得します。
1 2 3 4 5 6 7 8 |
query { member (id:2) { id name nickname age } } |
↓ 結果例
1 2 3 4 5 6 7 8 9 10 |
{ "data": { "member": { "id": "2", "name": "花子", "nickname": "ハナ", "age": 22 } } } |
clubsのクエリも実行してみます。
1 2 3 4 5 6 |
query { clubs { id name } } |
↓ 結果例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "data": { "clubs": [ { "id": "1", "name": "サッカー" }, { "id": "2", "name": "野球" }, { "id": "3", "name": "陸上" }, { "id": "4", "name": "水泳" } ] } } |
最後にGraphQLのエンドポイントに対してcurlを叩きJSONデータを取得してみます。日本語化等のコマンド(perl〜)は各自の環境において指定して下さい。
1 |
$ curl -H 'Content-Type:application/json' http://localhost:8000/graphql/ -d '{"query": "{members {id,name,nickname,age}}"}' | python -mjson.tool | perl -Xpne 's/\\u([0-9a-fA-F]{4})/chr(hex($1))/eg' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 289 100 244 100 45 24400 4500 --:--:-- --:--:-- --:--:-- 28900 { "data": { "members": [ { "id": "1", "name": "太郎", "nickname": "たろっぺ", "age": 20 }, { "id": "2", "name": "花子", "nickname": "ハナ", "age": 22 }, { "id": "3", "name": "次郎", "nickname": "ジロー", "age": 24 } ] } } |
関連ページ
参照ページ
graphql-python Tutorial – Introduction
GraphQL
Graphene-Python