🍲
GraphQLの基礎(Software Design 2021年8月号)
はじめに
Software Design 2021年8月号 掲載のGraphQLの章の備忘録
GraphQLが必要になった背景
GraphQLが必要になった背景として、APIに求められることへの変化がある
APIに求められた変化としては、多種多様なデータを少ないリクエストで取得したいというモダンなWebアプリの要求がある
現代のWebアプリは昔に比べて多様なことができるようになったことを考えれば、上記の課題が表出しているのも感覚的に理解しやすい
REST
RESTはシンプルなデータモデルをシンプルな実装で実現するという方針がある
従来のWebアプリであれば、シンプルなデータ構造が多かった故にRESTとの親和性が高かった
一方で、上記のような多種多様なデータを扱いたい場合にRESTを組み込むと以下のような課題が表面化する
- シンプルなデータモデルを軸として設計するために、特定のユースケース向けのために別途APIを作る必要がある
- 多種多様なデータを扱いたい = 特定のユースケースが増えていく → APIのエンドポイントが指数関数的に増えていく
- 黎明期はシンプルなデータモデルであって、成長期に至るに連れてデータモデルは複雑化する傾向がある
- エンドポイントが増えることにより以下の弊害が発生する
- アンダーフェッチ(N+1のリクエストの発生)
- オーバーフェッチ(ごく一部の特定のユースケースのためにリクエストを増やす必要がある。本来は1回で終わらしたい)
- クライアント側の実装の複雑化
改めて上記のような弊害を自身の経験と照らし合わせて見ても、サービスが成長するにつれてモダンなWebアプリの場合は、RESTだと相性が悪いのが伺える
GraphQL
こうしたRESTでの課題解決手段としてGraphQLが出てきた
特徴をまとめると
- クライアントのユースケースに柔軟に対応できる
- サーバー側の実装負担が大きくならない
- サービスが拡大しても指数関数的に管理コストが増えない
- データモデリング→schemaの作成に繋がり、それが開発ドキュメントになるので、開発時のコミュニケーション不整合が起こりにくい
- schemaは型を持つため、型の恩恵(型によるデータの安全性の担保)を受けることができ、開発支援になる
- GraphQLサーバー側で、クエリをパースして、検証を行い、schemaとクエリの比較を行う(ここでValidationがかかる)
- schemaは型を持つため、型の恩恵(型によるデータの安全性の担保)を受けることができ、開発支援になる
実装プラットフォーム
-
Hasura
- PostgreSQLなどのデータベースと接続し、テーブルのメタデータを利用してGraphQL APIを簡単に実装できるサービス
- 複雑なドメインロジックは他のRESTやGraphQL APIと接続することでたいてい実装できるとのこと
-
AppSync
- AWSが提供するフルマネージドなGraphQL as a Service
- 複雑なドメインロジックはLambdaを利用して実現
- AWSの他のリソースと組み合わせる要件の場合の親和性は高い
GraphQLクライアント
- Relay
- Apollo Client
- urql
- graphql-request
GraphQLの注意点
通常のCache Control Headerを使ったキャッシュ戦略が使えない
- GraphQLのエンドポイントは1つしか無く、POSTである
- 代わりに、GraphQLクライアントに実装されているキャッシュ戦略を利用する
ファイルアップロード
- トランスポート層によるファイルアップロードではないため工夫が必要
- 別のエンドポイントでファイルアップロード処理を委譲し、戻り値としてURLを受け取り、MutationでそのURLを保存するなど
処理に時間がかかるフィールドに全体のレスポンスが引っ張られる
- すべてのフィールドの解決がおわってからレスポンスを返すという仕組みのため
- @deferや@streamというDirectiveを処理の重いフィールドに付与して、段階的にデータを受け取り、全体を高速化するとう技がある
エラーでも200が返ってくる
- errorsフィールドの有無でエラーハンドリングの実装をすること
Enum型
- 値をとり得る範囲で限定することができる
- String型でも代用できるが、Enum型にすることで、サーバーとクライアント間の齟齬がなくなり、実装負荷軽減できる
スキーマを途中で変更する
以下の変更は破壊的になるので要注意
- オブジェクト型 or フィールドの名前変更
- フィールドの型を変更
- フィールドを Non-Null型からNullableに変更
- オブジェクト型 or フィールドの削除
- フィールドの引数を削除
Discussion