FastAPIとStrawberryでGraphQL超入門(QueryとMutation)
はじめに
本記事では、FastAPI+Strawberryで単純なQueryとMutationを実装し呼び出すことを目標にします。
GraphQLとは
GraphQLとはAPI向けのクエリ言語のことです。
主な特徴は以下の通りです。
- エンドポイントが1つだけ
- 複数のリソースを取得できる
- スキーマによる型付けができる
- Query、Mutation、Subscriptionがある
きちんとした説明はこちらの記事を読むとよさそう。
Strawberryの準備
今回はPythonのFastAPI+Strawberryで実装します。
必要なライブラリをインストールしておきます。
$ pip install fastapi
$ pip install uvicorn
$ pip install strawberry-graphql[fastapi]
公式ドキュメントのコードをコピペしてHello Worldしてみましょう。
import strawberry
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
@strawberry.type
class Query:
@strawberry.field
def hello(self) -> str:
return "Hello World"
schema = strawberry.Schema(Query)
graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
9000番ポートで起動します
$ uvicorn main:app --reload --host 0.0.0.0 --port 9000
localhost:9000/graphql
にアクセスすると下の画像のようなテスターが出てきます。
ここで実装したQueryやMutationのレスポンスを確認することができます。
コピペしたコードにはhello
というQueryがあるので、テスター側で
query {
hello
}
と書いてやることで
{
"data": {
"hello": "Hello World"
}
}
というレスポンスが得られます。
これでStrawberryの準備とHello Worldが終わりました🙌
Queryの実装
Queryを実装します。QueryはRESTでいうところのGETにあたります。
Hello World時にすでにQueryは実装されていましたが、Queryは以下のように実装します。
@strawberry.type
class Query:
@strawberry.field
def hello(self) -> str:
return "Hello World"
@strawberry.type
でデコレートされたQueryクラスのなかで@strawberry.field
でデコレートされたメソッドを書くことでQueryが実装できます。(メソッド戻り値の型指定を忘れずに!)
では、新しくQueryを追加してみましょう。
@strawberry.type
class Query:
@strawberry.field
def hello(self) -> str:
return "Hello World"
+ @strawberry.field
+ def bye(self) -> str:
+ return "Bye!"
これでbye
クエリの実装ができました。
Hello Worldのときと同じようにテスター上で
query {
bye
}
とすることで
{
"data": {
"bye": "Bye!"
}
}
というレスポンスが得られます。
また、Queryは複数個同時に呼ぶことができます。
例えば
query {
hello,
bye
}
上記のクエリは
{
"data": {
"hello": "Hello World",
"bye": "Bye!"
}
}
というレスポンスを返します。
クエリの戻り値にJSONを指定したいとき
from strawberry.scalars import JSON
strawberryのJSON型が存在しているので、こいつを使えばJSONを戻り値に指定できます。
Mutationの実装
Mutationを実装しましょう。RESTではPOST、PATCH、DELETEにあたるようです。
Mutationは以下のように実装できます。
+@strawberry.type
+class Mutation:
+ @strawberry.mutation
+ def thousand(self, number:int) -> int:
+ return number * 1000
-schema = strawberry.Schema(Query)
+schema = strawberry.Schema(Query, Mutation)
graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
Mutationクラスを追加し、その中で@strawberry.mutation
でデコレートされたメソッドを定義しましょう。
もうひとつメソッドを追加してみます。
@strawberry.type
class Mutation:
@strawberry.mutation
def thousand(self, number:int) -> int:
return number * 1000
+ @strawberry.mutation
+ def hundred(self, number:int) -> int:
+ return number * 100
schema = strawberry.Schema(Query, Mutation)
graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
MutationもQueryと同じように1つでも複数でも呼び出すことができます。
# 1つの場合
mutation{
thousand(number:1)
}
# 複数の場合
mutation{
thousand(number:1),
hundred(number:1)
}
// 1つの場合のレスポンス
{
"data": {
"thousand": 1000
}
}
// 複数の場合のレスポンス
{
"data": {
"thousand": 1000,
"hundred": 100
}
}
APIの叩き方
いままではテスターからQueryやMutationを呼び出していましたが、今度は普通にAPIを叩いてみましょう。
FastAPIを使っているので、http://localhost:9000/docs
にアクセスするとSwagger UIにアクセスできます
/graphql
エンドポイントはGET
とPOST
を受け付けていることがわかります。
GETでの叩き方
GETメソッドで呼び出す場合は、クエリパラメータを付けることで呼び出すことができます。
- Query
http://localhost:9000/graphql?query=query{hello}
にGETでアクセスします。
レスポンスは
{
"data": {
"hello": "Hello World"
}
}
となり、正常に呼び出せていることがわかります。
- Mutation
GETメソッドでのMutationの呼び出しは許可されていません。
POSTでの叩き方
http://localhost:9000/graphql
にPOSTでアクセスします。
- Query
// リクエストボディ
{
"query":"query{hello}"
}
// レスポンスボディ
{
"data": {
"hello": "Hello World"
}
}
- Mutation
// リクエストボディ
{
"query":"mutation{thousand(number:1)}"
}
// レスポンスボディ
{
"data": {
"thousand": 1000
}
}
これで、GETとPOSTのどちらでもAPIを叩くことができました!
Discussion