はじめに#

DjangoでGraphQL APIを開発したい初心者向けに、Strawberry を用いた基本的な設定とスキーマ設計を解説します

本家のサイトでは断片的に書かれていますが、体系的にかかれていないため、ここでは導入方法、具体的なファイル構成について説明します。

導入後の完成形の image も github に上げておきます。

1. strawberryのインストール#

djangoはインストールされている前提(startproject ですでにプロジェクトは存在済み)です。つまり django の helloworld は終わっている状態を仮定しています。

必要なライブラリはstrawberry-graphqlのみですので、これをインストールします。 pip install strawberry-graphql

私はdockerで開発し、ローカルではryeで作業をしていますが、人によっては virtualenv, poetry, pip 等々あるとおもいますので適時入れ替えてください

2. api アプリの作成#

djangoであたらしいapiアプリを作ります。もし既存のアプリにインストールするのであれば別にstartappしなくても構いません。

python manage.py startapp api # manage.py があるディレクトリで実行

settings.py に api を追加します。

``INSTALLED_APPS = [
...
"api"
]

補足: migrations#

人によっては,api の models.py を作る人がいるかもしれません。 モデル編集後は作成後は migratinos & migrate をしておきます。

$ python manage.py makemigrations api
$ python manage.py migrate

3. プロジェクトのurls.pyに追加#

プロジェクトの urls.py を編集して、次の項目を追加します。

path("api/", include("api.urls")),

4. migration, query 用のファイルを作成#

mutations.py と queries.py というファイルを作成します。graphqlのmutationとqueryは各々に書きます。

今、apiフォルダにいるとします。フォルダを3つ作り、先の2つのファイルをタッチします。

mkdir graphql
mkdir graphql/mutations
mkdir graphql/queries
touch graphql/__init__.py # __init__.py は、Python にディレクトリをパッケージとして認識させるためのファイル
touch graphql/mutations/mutations.py
touch graphql/queries/queries.py

こういう構成になっているはずです。

├── graphql
│   ├── queries
│   │   └── queries.py
│   ├── mutations
│   │   └── mutations.py
│   └── __init__.py

説明用にこういうフォルダ構成やファイル名にしましたが、次に作るschema.pyと整合性があれば問題ありません。

5. schema.pyの作成#

api フォルダの中に schema.py を作成します。中身は次のとおりです。


import strawberry

from .graphql.mutations.mutations import Mutation # フォルダ構成はまかせるが、上の説明と矛盾がないように
from .graphql.queries.queries import Query

schema = strawberry.Schema(query=Query, mutation=Mutation)

6. アプリにurls.pyを作成#

続いて apiフォルダ内で urls.py を作ります。

内容は次のとおりです。

from strawberry.django.views import GraphQLView
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .schema import schema

urlpatterns = [
    path(
        "graphql/",
        csrf_exempt(GraphQLView.as_view(schema=schema, graphql_ide="apollo-sandbox")),
    ),
]

graphql-ideという引数にapollo-sandboxを指定します。graphql-ideは指定しなくてもいいですがapolloはおすすめです。

csrf_exmptメソッドでくくっていますが、これはなくても動きます。これは、CSRF (Cross-Site Request Forgery) 対策を無効化します。API の場合は必要に応じて設定を見直してください。

これでgraphqlを使う準備はできました。djangoを立ち上げlocalhost:8000/api/graphql/を叩くことで、graphqlのApolloクライアントが立ち上がります。

7. 実行する ( hello, world )#

mutations.py には、次のようにmutationを書きます。

import strawberry
from strawberry.types import Info
from strawberry.django.context import StrawberryDjangoContext

@strawberry.type
class Mutation:
    @strawberry.mutation
    def hello(self, info: Info[StrawberryDjangoContext, None],) -> str:
        return "Hello from imfaxblog!"

queries.pyにもqueryを追加します。


import strawberry
from strawberry.types import Info
from strawberry.django.context import StrawberryDjangoContext


@strawberry.type
class Query:
    @strawberry.field()
    def hello(self, info: Info[StrawberryDjangoContext, None],) -> str:
        return "Hello from imfaxblog!"

新しくquery, mutationを書きたいときはメソッドを追加すればいいだけとなります。

さて、以下のgraphqlでメッセージが出ます。

query Query {
  hello
}

mutation Mutation {
  hello
}

以上で、Djangoでstrawberryを用いたGraphqlサーバーの完成となります。

Infoについて#

Info は、GraphQL リゾルバー関数 (ここでは hello 関数) に渡される引数の一つで、リクエストに関する様々な情報 (コンテキスト、フィールド情報など) を保持しています。

今回の例では、ルートオブジェクトを使用していないため、None を指定しています。つまり、Info[StrawberryDjangoContext, None] は、Info 型のジェネリクス (Generics) を用いて、Info が保持するコンテキストの型を StrawberryDjangoContext、ルートの型を None に指定という意味になります。

ここでのStrawberryDjangoContextは、 Django のリクエストコンテキスト (リクエスト、ユーザー情報など) を Strawberry で利用するための型です。info.context を通じて、Django のリクエストオブジェクトにアクセスできます。

Strawberryの本家でも infoを info: strawberry.Infoとしているところがありますが、この場合だとinfoはAnyになり、リゾルバー関数内で info オブジェクトを通して利用できる情報が不明確になり、型チェッカーによる静的解析ができません。

補足説明: 任意の型を返すとき#

auth認証のある場合、userType を返したいという時の例を紹介します。

次のように userType を作り返却するだけです。

import strawberry
from strawberry.django.context import StrawberryDjangoContext
from someapp.your_custom_user_model import User # 大体の場合、ユーザはカスタムユーザーを使っているともいます

@strawberry.type # djangoの@strawberry_django.typeデコレータではなくても問題ないです。
class UserType:
    id: int
    username: str
    age: int


@strawberry.type
class Mutation:
    @strawberry.mutation(permission_classes=[IsAuthenticated]) # IsAuthenticatedはhttps://strawberry.rocks/docs/guides/permissionsを参照
    def update_user_age(self, info: Info[StrawberryDjangoContext, None], age: int) -> UserType:
        user = cast(User, info.context.request.user) # 後述
        ...
        return UserType(id=user.id, username=user.username, age=age)

Auth 処理をしているので、info.context.request.user には user オブジェクトが入ることになります。 上記例ではpermission_classesを利用することで、問題があったときは例外が発生することになります。

ただ、sentryなど使っていると例外の発生は困る場合もあります。そういうときはextensionを使います。 詳しいやり方についてはこちらをご覧ください

castについて#

cast は、Python の型ヒント (Type Hinting) を利用して、変数の型を明示的に指定する関数です。info.context.request.userは、実行時にDjangoの User オブジェクトであることが期待されますが、型チェッカー (例: MyPy) は、そのことを自動的に認識できません。そこでcastを用いて型チェッカーに対して info.context.request.userをUser型として扱うように指示します。

これにより、型チェッカーは、user変数に対して User型の属性やメソッドを安全に利用できることを確認できます。また型ヒントはコードの可読性を向上させ、開発者の意図を明確にする役割も果たします。

まとめ#

この記事では、DjangoでGraphQL API を開発するために、Strawberry を用いた基本的な設定とスキーマ設計について解説しました。

GraphQL の導入は、API 開発の効率化と柔軟性を高める上で非常に有効です。Strawberry を使うことで、Python らしい簡潔なコードで GraphQL API を実装できます。

この記事が、Django × Strawberry GraphQL の入門の一助となれば幸いです。

戻る