GraphQLの基礎知識

GraphQLを使っているエンジニアの人と話していて、自分がGraphQLをよくわかってないことに気づいたので、基本的な情報を調べてみた。

GraphQL

Metaが開発したOSSAPIを効率よく呼び出すために作られたクエリ言語。

SQLRDBを使うように、GraphQLはGraphQL用の特殊なDBを使うのかと思いがちだが、そういうわけでは無い。GraphQLもRDBなどを使う。なので、DB内の計算などを効率化するわけでは無い。backend側のコードを見通し良く効率的に書ける、というモチベーションが強い印象。

GraphQLの特徴

必要なデータを過不足なく、一度で取得できる(アンダーフェッチ、オーバーフェッチが無い)。そのため、データフェッチの効率性が高い。

基本的に、1つのデータを取得する際1つのエンドポイントを呼ぶだけで完結するので、APIの設計をシンプルにすることができる。クエリ言語を柔軟に記載することができる。

色々なサポート機能がある。例えば、Subscriptionsという機能を使って、リアルタイムデータを効率的に扱うことができる。

向いているサービス

ソシャゲ、eコマースなどの複雑なデータ構造を持つサービス、リアルタイムデータを扱うアプリケーションなどで真価を発揮する。

一方で、データ構造がシンプルなサービス、キャッシュが重要なサービスなどには向いていない。

データベース

特定のデータベースに依存していない。RDBでも、NoSqlでもOK。必ずしも、GraphQLを使うとREST APIよりもデータベースからfetchする回数が減るとは限らない。実装次第。

Resolver

スキーマとデータソースを結びつける役割を持つ。スキーマはあくまで定義のみで、Resolverが実際の操作を行なってくれる。

Subscriptions

GraphQLサーバーにデータ変化などの特定のイベントが生じるたびに、クライアントにデータ送信するPubSubのような仕組み。クライアントがサーバーにGraphQLのクエリ、クエリ変数を送信する。サーバーは、イベントがトリガーされたらクエリを実行する。

DataLoader

データ取得に使用される汎用的なツール。データ取得をbatch処理する機能と、結果をcacheする2つの機能がある。

batchは、データ取得のリクエストを一定時間待って、その間に行われたリクエストを統合してbatch処理してくれる。

cacheは、batchに登録されるkeyと、それに対応するvalueの組をメモ化する。

これらの機能を使うと、データアクセスの回数が減少する。

DataLoader導入前

SELECT item_id, amount FROM orders WHERE customer_id = "foobar";

SELECT name, description, price FROM items WHERE id = "hoge";
SELECT name, description, price FROM items WHERE id = "fuga";
SELECT name, description, price FROM items WHERE id = "piyo";

DataLoader導入後

SELECT
  name, description, price
FROM
  items
WHERE
  id IN ("hoge", "fuga", "piyo");

N+1問題

N件のデータレコードを取得した時、関連レコードの取得にN回のfetchを行なって、N+1回のfetchをしてしまうこと。DataLoaderで解決できる。

Relay

Metaが開発しているGraphQLクライアント。

  • 全てのObjectに対して、一意のGlobal IDを要求するので、データの再利用性が高い
  • リスト、ページネーションなどの際、Connectionという仕様を使うことで効果的に処理できる
  • Mutationを行いやすい
  • Fragment colocationによって、データフェッチが最適化される

Fragment colocation

コンポーネントとGraphQLフラグメントを密接に配置するデザインパターン

以下のような利点がある。

  • 明確な依存関係を示すことができる
  • 再利用性の向上
  • 効率的なデータフェッチ
  • 保守性の向上

GraphQLのメリット

クライアントはスキーマをもとに、欲しいフィールドだけをリクエストできる。

リレーションがある値は、一度のリクエストで取得できる。例えば、twitterのフォロー数、フォロワー数を取得する際、REST APIだと2回のリクエストが必要だが、GraphQLであれば一度で取得できる。

スキーマをもとに開発するので型の不一致が起きない。強い型付けが採用されている。

GraphQLのデメリット

クエリが複雑になる可能性・学習の難しさが挙げられる。

また、GraphQLのメリットを享受するのが難しい。GraphQLはMetaがReact・Relayと組み合わせて使い始めた。「RelayスタイルでないGraphQLに価値はない」と言うGraphQL有識者もいる。Relayを使わないにせよ、Fragment Colocationがわかってないとメリットを享受しづらい。

RESTでやっていたことが直感的にやり辛くなる側面もある。

gqlgen

GraphQLサーバーを構築するGoライブラリ。GraphQLスキーマ定義言語を使用してAPIを自動生成してくれる。

参考文献

https://sizu.me/adwd/posts/34mkeimfb06x

https://lyohe.github.io/blog/2021/12/16/reading-dataloader/#:~:text=graphql%2Fdataloader