こんにちは。KOUKIです。
今回は、Graphene-Djangoを使って、GraphQLを学びましょう。
<目次>
記事まとめ
GraphQLとは
GraphQLは、Facebookが開発しているWeb APIのための規格で、 クエリ言語とスキーマ言語からなります。
REST APIだと、欲しい情報の数だけエンドポイント(URL)が必要になりますが、GraphQLではエンドポイントは一つだけで済みます。
例えば、以下のqueryをGraphQLサーバーに送信したとします。
1 2 3 4 5 6 |
例) query { allPets { animal } } |
データ送信後、次のような形式で、データを取得できます。
1 2 3 4 5 6 7 8 9 |
{ "data": { "allPets": [ { "animal": "Cat" } ] } } |
REST APIに比べると以下のメリットがあるようです。
・ エンドポイントを増やさずに欲しい情報を取得できる
・ 不必要な情報は取ってこない
・ フロントエンド・サーバーサイドの作業を完全に分業化できる
・ アプリケーションに縛られない自由なデータ取得サーバー(GraphQLサーバー)を立てられる
Djangoには、Graphene-Djangoという3rd-party製のモジュールがあり、かなり便利であると感じたため、ご紹介もかねてハンズオンしてみます。
プロジェクトの準備
Docker上にDjangoとReactの環境を構築するを参考にプロジェクトを作成しましょう。
今回は、フロントエンドはReact、サーバーサイドはDjango、基盤はDockerで作成します。
1 2 3 4 5 6 7 8 9 10 |
mkdir django-graphql/ cd django-graphql mkdir app touch Dockerfile touch Dockerfile-nodejs touch Makefile touch docker-compose.yml touch requirements.txt |
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 30 31 32 33 34 35 36 37 38 39 40 41 |
# docker-compose.yml version: "3" services: app: build: context: . ports: - "8000:8000" volumes: - ./app:/app command: > sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" environment: - DB_HOST=db - DB_NAME=app - DB_USER=postgres - DB_PASS=supersecretpassword depends_on: - db - react db: image: postgres:10-alpine environment: - POSTGRES_DB=app - POSTGRES_USER=postgres - POSTGRES_PASSWORD=supersecretpassword react: build: context: . dockerfile: "./Dockerfile-nodejs" volumes: - ./frontend:/frontend command: > sh -c "cd frontend && npm start" ports: - "3000:3000" |
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 |
# Dockerfile FROM python:3.7-alpine MAINTAINER kanagawa App Developer Ltd ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 COPY ./requirements.txt /requirements.txt RUN apk add --update --no-cache postgresql-client jpeg-dev RUN apk add --update --no-cache --virtual .tmp-build-deps \ gcc libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev RUN pip install -r /requirements.txt RUN apk del .tmp-build-deps RUN mkdir /app WORKDIR /app COPY ./app /app RUN mkdir -p /vol/web/media RUN mkdir -p /vol/web/static RUN adduser -D user RUN chown -R user:user /vol/ RUN chmod -R 755 /vol/web USER user |
1 2 3 4 5 6 7 |
# Dockerfile-nodejs FROM node:10.13-alpine MAINTAINER kanagawa App Developer Ltd RUN npm install -g create-react-app RUN npm install apollo-boost @apollo/react-hooks graphql |
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 |
# Makefile .PHONY: app test migrate pro admin django react app: docker-compose run --rm app sh -c "python manage.py startapp ${app}" test: docker-compose run --rm app sh -c "pytest -l -v -s ${app} && flake8" migrate: docker-compose run --rm app sh -c "python manage.py makemigrations" docker-compose run --rm app sh -c "python manage.py migrate" pro: docker-compose run --rm app sh -c "django-admin startproject ${pro} ." admin: docker-compose run --rm app sh -c "python manage.py createsuperuser" django: docker-compose run --rm app sh -c "django-admin startproject app ." react: docker-compose run --rm react sh -c "create-react-app frontend" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# requirements.txt aniso8601==7.0.0 Django==2.2.7 django-filter==2.2.0 django-graphql-jwt==0.2.2 graphene==2.1.8 graphene-django==2.6.0 graphql-core==2.2.1 graphql-relay==2.0.0 promise==2.2.1 PyJWT==1.7.1 pytz==2019.3 Rx==1.6.1 singledispatch==3.4.0.3 six==1.13.0 sqlparse==0.3.0 |
ここまで設定できたらビルドしましょう。
1 2 3 4 5 6 7 8 9 10 11 |
# build docker-compose build # Djangoプロジェクト作成 make django # Reactプロジェクト作成 make react # プロジェクトの起動 docker-compose up |
localhost:8000 及び localhost:3000にアクセスしてみましょう。
それぞれのスタート画面が出てきたら成功です。※起動に失敗した場合は、docker-compose buildを再実行してください
アプリケーションの作成
最初にGraphQLを実装するアプリケーションを作成します。
次のコマンドでアプリケーションを作成します。
1 |
make app app=api |
次の構成でアプリケーションが作成されたと思います。
1 2 3 |
app L api L app |
このapiを同一階層にあるappフォルダ配下に格納してください。
1 2 3 |
app L app L api |
次にsettings.pyにapiを登録します。
1 2 3 4 5 6 7 8 9 10 11 |
INSTALLED_APPS = [ # myapp 'app.api', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] |
Bookモデルの作成
api配下にBookモデルを追加しましょう。
1 2 3 4 5 6 7 8 9 10 |
# app/api/models.py from django.db import models class Book(models.Model): title = models.CharField(max_length=255) publish = models.IntegerField(default=2000) def __str__(self): return self.title |
マイグレーションを実行します。
1 |
make migrate |
このモデルを管理画面に表示できるようにしましょう。
1 2 3 4 5 6 |
# app/api/admin.py from django.contrib import admin from .models import Book admin.site.register(Book) |
管理ユーザーを作成します。
1 |
make admin |
localhost:8000にアクセスし、作成した管理ユーザーでログインしましょう。
Authorモデルの追加
もう一つ、Authorモデルを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# app/api/models.py from django.db import models # new class Author(models.Model): firstname = models.CharField(max_length=32) lastname = models.CharField(max_length=32) def __str__(self): return self.firstname + " " + self.lastname class Book(models.Model): title = models.CharField(max_length=255) publish = models.IntegerField(default=2000) author = models.ForeignKey(Author, on_delete=models.PROTECT, blank=True, null=True) def __str__(self): return self.title |
マイグレーションを実行しましょう。
1 |
make migrate |
管理画面にも登録します。
1 2 3 4 5 6 7 |
# app/api/admin.py from django.contrib import admin from .models import Author, Book admin.site.register(Author) admin.site.register(Book) |
管理画面にアクセスし、Author及びBookにデータを格納してみましょう。
GraphQLの実装
前準備はここまでにして、GraphQLを実装していきましょう。
まずは、settings.pyに、次の設定をしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
INSTALLED_APPS = [ 'app.api', # new 'graphene_django', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] # new GRAPHENE = { 'SCHEMA': 'app.schema.schema' } |
GRAPHENには、プロジェクトレベルで設定するスキーマーを登録します。
次のコマンドで、schema.pyを作成してください。
1 2 3 4 5 6 |
touch app/schema.py app L api L app L schema.py |
先ほどのスキーマー設定はこのファイルを指しています。
1 2 3 4 5 6 7 8 9 10 |
# app/schema.py import graphene import app.api.schema class Query(app.api.schema.Query, graphene.ObjectType): pass schema = graphene.Schema(query=Query) |
続いて、api配下にもschema.pyを作成します。
1 |
touch app/api/schema.py |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# app/api/schema.py import graphene from graphene_django.types import DjangoObjectType from .models import Book class BookType(DjangoObjectType): class Meta: model = Book class Query(graphene.ObjectType): all_books = graphene.List(BookType) def resolve_all_books(self, info, **kwargs): return Book.objects.all() |
登録したBookを全て取得する処理を書きました。
最後にapp配下のurls.pyにエンドポイントを設定します。
1 2 3 4 5 6 7 8 9 10 |
# app/app/urls.py from django.contrib import admin from django.urls import path from graphene_django.views import GraphQLView urlpatterns = [ path('admin/', admin.site.urls), path('graphql/', GraphQLView.as_view(graphiql=True)), ] |
graphiqlをFalseにするとGraphQLを使用不可にできます。
それでは、「http://localhost:8000/graphql/」にアクセスしてみましょう。

Queryの説明
今回は、次の設定を行いました。
1 2 |
class Query(graphene.ObjectType): all_books = graphene.List(BookType) |
これをqueryにすると次のようになります。
1 2 3 4 5 6 7 |
query { allBooks { id title publish } } |
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 |
{ "data": { "allBooks": [ { "id": "1", "title": "Harry Potter and the Philosopher's Stone", "publish": 1997 }, { "id": "2", "title": "Harry Potter and the Chamber of Secrets", "publish": 1998 }, { "id": "3", "title": "Harry Potter and the Prisoner of Azkaban", "publish": 1999 }, { "id": "4", "title": "Harry Potter and the Goblet of Fire", "publish": 2000 } ] } } |
直感的でわかりやすいですね。
長くなってきたので、ここまでにしましょう。
次回
次回も引き続き、Graph QLを学んでいきましょう。
コメントを残す
コメントを投稿するにはログインしてください。