今更ながらGraphQLについてまとめてみた
はじめに
GraphQLについてのオライリー本を読んだり、AppSyncを趣味で触ったりしたので今更ながらGraphQLについて社内勉強会用にまとめてみました。
GraphQLとは
GraphQLを一言で説明するとWEB APIのためのクエリ・スキーマ言語である。
クライアントアプリケーションのデータモデルの機能と要件を記述することを目的にFacebookの開発チームによって作成された。1
クエリ言語とスキーマ言語
ここで扱うクエリ言語とスキーマ言語については以下のようなイメージとなっている。
- クエリ言語
- クライアントアプリがGraphQLサーバーにリクエストを送信するための構文
- スキーマ言語
- GraphQLサーバーのデータ型の集合を定義するための構文
GraphQLの立ち位置
アプリケーション開発に用いられるGraphQLのイメージ。
GraphQLサーバーが実際に行うこと
-
APIサーバーとの通信を行う
- もしくは直接データベースの操作を行う
-
クエリ構文を解析する
- 解釈した構文に基づいて処理(リゾルバ)が実行される
WEB APIとしてのクエリ
GraphQLサーバーへ送るクエリはHTTPリクエストのPOST
メソッドを用いて送信される。以下はcURLでの例。
curl --location --request POST 'http://snowtooth.moonhighway.com/' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query {\r\n allLifts {\r\n name\r\n }\r\n}","variables":{}}
クエリのリクエストを試す場合は、GraphiQLやGraphQL PlaygroundなどのツールもしくはPostmanのGraphQL機能を使用することができる。
クエリの種類
クライアントアプリケーションが用いるクエリの構文では、3つのオペレーションを用いることができる。
- query
- mutation
- subscription
query
データを取得するためのオペレーション。実際に取得したいデータをfieldに指定する。以下はスノートゥースで、すべてのLift
のname
とstatus
の情報をとってくる例。
query getAllLifts {
allLifts {
name
status
}
}
mutation
データの書き込み操作を担当する。基本的に構文はqueryと変わらない。以下は前ページで用いたスノートゥースでとあるLift
のstatus
を更新する例。
mutation openLift {
setLiftStatus(id:"astra-express" status: OPEN) {
name
status
}
}
subscription
サーバーからリアルタイムでデータを受信することができる。例えばmutationで更新したstatus
を毎回受け取りに行くために、一々queryを叩かずともsubscriptionを用いればWebSocketを通じてリアルタイムにデータを受け取ることができる。以下はその構文の例。
subscription listenStatusChange {
liftStatusChange {
name
status
}
}
ここで省略した話
- フラグメント
- 冗長な構文を共通化させる仕組み
- ユニオン型
- 2つの異なるオブジェクト型をまとめる仕組み
- インタフェース
- 実装すべきフィールドのリストを指定する抽象型
スキーマの設計
実際にGraphQLサーバーを実装するために、まずはデータ型の集合であるスキーマを設計する。実装例については過去の記事の内容を使いまわしてみる。
enum Category {
HOGEHOGE
HUGAHUGA
}
type Item {
id: String!
data: String!
category: Category!
}
type Query {
allItem: [Item]
allItemOnCategory(category: Category): [Item]
}
input ItemInput {
data: String!
category: Category!
}
type Mutation {
addItem(item: ItemInput!): Item
}
型
型はスキーマの核になるもの。それぞれの型には対応するフィールドが存在する。QueryやMutationもそれぞれ使用可能なクエリがフィールドとして定義されている型となる。
type Item {
id: String!
data: String!
category: Category!
}
type Query {
allItem: [Item]
allItemOnCategory(category: Category): [Item]
}
type Mutation {
addItem(item: ItemInput!): Item
}
スカラー型とリスト
それぞれのフィールドが固有の型のデータを持っていて、その組み込みの型をスカラー型という。例えばid
にはString
というスカラー型で定義されている。ちなみにString!
と!
を付与することでそのフィールドがnullにならないことを示すことができる。
また、型を[]
で囲むことでフィールドに型のリストを指定することができる。例えば[Item]
はItem
という型のリストであることを示している。
Enum
Enumは限られた選択肢の文字列が入力・出力されることをフィールドに定義したいときに用いる
enum Category {
HOGEHOGE
HUGAHUGA
}
ここで作成したCategory
はフィールドの型として用いることができる。
入力型
引数に対して使用する型。多数の引数をまとめるために用いる。
input ItemInput {
data: String!
category: Category!
}
ここで作成されたItemInput
は引数にのみ用いることができる。
ここで省略した話
- カスタムスカラー型
- 独自で定義されたスカラー型。
- ユニオン型
- 複数の型のうち一つを返す型。
- インタフェース
- 型の中で必ず存在するフィールドを定義する抽象型。
リゾルバ
リゾルバは特定のフィールドを返す関数。クエリで指定されたフィールドに対して発行される。以下は過去の記事で書いたAppSyncとCDKの実装例。
...
itemDS.createResolver({
typeName: 'Query',
fieldName: 'allItem',
requestMappingTemplate: MappingTemplate.dynamoDbScanTable(),
responseMappingTemplate: MappingTemplate.dynamoDbResultList(),
})
itemDS.createResolver({
typeName: 'Mutation',
fieldName: 'addItem',
requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
PrimaryKey.partition('id').auto(),
Values.projecting('item')),
responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
})
...
直感的な理解としては、リゾルバはリクエストとレスポンスのボディに対するマッピング・そのための内部的な処理を実装するものである。
さいごに
- GraphQLを用いた開発では、スキーマとクエリの2つの言語を書くことになる
- スキーマはAPIの仕様となるもの
- クエリはクライアントアプリからのリクエスト
- 基本的にライブラリを用いた開発となる
- 手で実装するのはおそらく難解
- GraphQL用のライブラリについては公式ページで紹介されている。
GraphQLについて気になった問題などを取り上げた記事などの紹介
N+1問題
N+1問題とは「1つのSQLでN件のレコードをフェッチしたあと、それぞれ対して関連するレコードを個別にフェッチするのにNつのSQLを発行している」状態を指す問題です。GraphQLのリゾルバでSQLを用いる場合このが引き起こされやすくなります。
この問題についてはこの記事が参考になりました。
REST APIの代替技術となるのか
こちらの記事にある通り、GraphQLにも欠点があります。
- フルスクラッチでの実装が難しい(基本はライブラリ依存)
- 画像や動画などの大容量バイナリの扱いが難しい(JSONなので)
Redux vs GraphQL
この話題についてとあるスライドの28ページ目の表がわかりやすくまとまっていました。
こういった記事にもあるように基本的にはapollo-clientとReduxとの対比でよく議論されているようです。
Author And Source
この問題について(今更ながらGraphQLについてまとめてみた), 我々は、より多くの情報をここで見つけました https://qiita.com/ufoo68/items/875d0afc7d42dc0af1cd著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .