自分用に GraphQL を学んだ際に参考にした記事たちとその内容をまとめて残しておきます。
- GraphQLスキーマ設計の勘所
- GraphQL実践ノウハウv2
- GraphQL 成熟度モデルの紹介と、プロダクトに当てはめた事例 / GraphQL maturity model
- GraphQLはどんな時に使うか
- GraphQLクライアントの技術選定 2023冬
- 今こそ思い出すGraphQLの特徴
- AWS AppSync入門(GraphQL、AWS CDK)
- [AWS Dev Day 2021 A-1] ゼロから始めるAWS AppSync導入の軌跡と振り返り 〜課題も添えて〜
- GraphQL 入門 ~ REST と比較しながら学ぶ ~
- ソニー: GraphQLを活用したデータ配信プラットフォームの事例紹介
- Hatena Engineer Seminar #14 GraphQL編
- GraphQL「良さ」・「難しさ」再探訪 〜スタディサプリにおける実例〜 / StudySapuri with GraphQL
- GraphQL と Prisma から考える次のN年を見据えた技術選定
- GraphQLにおけるクライアントキャッシュ戦略
- GraphQLにおけるエラーハンドリングの仕方
- GraphQLは「オワコン」「流行らない」のか?
- 全網羅!Spring for GraphQLのエラーハンドリングを徹底攻略!!
- GraphQLはいつ使うか、RESTとの比較
- GraphQLのスキーマ定義やクエリから型定義、自動生成できまっせ
- GraphQL で REST API を作る - 技術的な挑戦と、それを支える文化の話
- GraphQLはサーバーサイド実装のベストプラクティスとなるか
GraphQLスキーマ設計の勘所
- GraphQL はプロトコルなので、スキーマの設計は後方互換性が必要
- クライアントサーバ双方の都合を理解して設計をする必要がある
- クライアント・サーバが別チームで開発をしていると、スキーマの合意が結構大変だったりする?
- GraphQL を使っていても、ID 参照をしていれば複数回のリクエストが飛んでしまう
- Field 単位のリゾルバで無駄なリソースの取得を回避しよう
- mutation は専用の Payload を返すようにする
- updateUser みたいな mutation に対し User そのものを返すようにしていると、いつか壊れるかもしれない
- 専用の type を作って拡張しやすくしていこう
- type 同士の依存関係をなるべく減らそう
- ビジネスロジックも type で表していこう
- User { isAdalt } で age >= 20 の時のみ true となるロジックも積極的に Schema 定義する
- それを必要とする場合は専用の Resolver を呼び出せばよい
- ビジネスロジックを Server に集約できる & 必要な時にだけ実行できる
- クライアント側の決定性のためにカーソル・ページネーション
- 決定性とはクライアント側でレスポンスの内容を決定できる性質のこと
Resolver ってフィールドの組み合わせ数だけ爆増したりしないのか?User.Company みたいに別テーブルへアクセスしないといけない場合は Resolver を分けたほうが良さそう
後はビジネスロジックも負荷が無視できない場合にだけ専用の Resolver でええんとちゃうか
ページベースのページングの問題点
データ登録される頻度が高いとリクエストした時間の前後ですぐズレる可能性がある。例えば、2024/4/20 10:00~2024/4/20 10:01
の範囲のデータを取ろうとして、1 ページ 1000 件だとする。
指定期間のデータは 1200 件しかなく、2 ページで取り切れるが、取得した後に 1201 件目が追加された場合にデータの取りこぼしが発生する。トランザクションタイムアウトもあるし、そないギリギリでデータを取りに行くなよという話でもある。
GraphQL は Cursor Connection
という仕様を使ってカーソルベースのページネーションを簡単に実装することが出来る 。
GraphQL実践ノウハウv2
この発表のコンテキストとして、プロダクトが使っている API が内部 API と外部 API を利用している 内部 API -> 抽選データ、外部 API -> 商品データ
実装パターンとして
抽選データだけ欲しいのに商品データまで取ってしまう (無駄に外部 API を呼び出す) という課題がある。... Resolver を工夫すればええんとちゃうんかと思ったが -> 実際に商品に対する Resolver を作って解決をしていた
認証や N+1 はキャパオーバーだから後回し
GraphQL 成熟度モデルの紹介と、プロダクトに当てはめた事例 / GraphQL maturity model
- サーバの GraphQL サポート
- Playground の提供
- GraphQL スキーマと言語の型システムの統合
- フロントもバックエンドもスキーマをベースにして型システムを導入しようね
- この辺りに Roslyn のコード生成の話が入ってくる
- スキーマのデフォルト値を nullable にする
- これによりバックエンドでの例外を null として表現出来るようになる
- フロントでは null のハンドリングだけやればアプリは継続して利用できる
- null はレスポンスデータの破壊的変更にも対応している
- モバイルは破壊的変更の対応が難しい。ストアにアップして~とかが時間かかる
- Web はフロント・バックどちらもコントローラブル。デプロイ時の工夫でどうとでもなる
- これによりバックエンドでの例外を null として表現出来るようになる
- Node 仕様の実装
- ここで分かったのは Node 仕様に準拠するとグローバル ID を持つという事
- フロントエンドで正規化されたキャッシュの利用
- Fragment を利用した UI データの定義
- 複数の Fragment をまとめて取得
- Razor Component はこの辺りに関わってきそう
- @defer と @stream のサポート
- UX を向上させるための仕組む
- Fragment 単位の Subscription
node と egde の違いを正しく理解しよう
node -> グラフの頂点、edge -> 頂点同士を繋ぐ線 Company に複数の User が所属する時、Company と User を繋ぐ線を edge として表現する事になるだろう むずいなぁ
Relay Connection によるページネーション
カーソルベースはその地点のデータのポインタのようなイメージね GraphQL では必要な値を base 64 encode しているらしい んで、Relay Cursor Connectionsは、Facebookが提供しているReact向けのGraphQLクライアントライブラリであるRelayでサポートしているページネーションのためのルール カーソルベースのページネーションを使ってねってなって、Relay の実装パターンを使おうねって事。Connection の仕様についてはあまり詳しく書いてない。
StrawberryShake だとスキーマ変更時の破壊的変更にはビルド時に気付けるな。他の言語だとどうなっているのかな?CI の実行時に気付けるのか?
GraphQLはどんな時に使うか
- GraphQL は API のクエリ言語であり、既存のデータでこれらのクエリを実行するためのランタイム
- ランタイムがようわからんが、クエリを解析して実行するまでの仕組むが一通り揃っているのだろう
- GraphQL は非同期処理、バッチ処理、サーバ間連携、には向いていない
- サービス指向アーキテクチャと API アグリゲーションを実現できる
- フィールドの変更での breaking changes が検知できる
- さて、どんな時に GraphQL を使うか
- クラサバで異なるデータモデリングを行いたいか
- マルチクライアントかどうか
GraphQLを最速でマスターするための意識改革3ヶ条
今まであったfieldを削除するとかは破壊的かもしれないがGraphQLではadd-only approachを推奨している。つまり加えるのみ。
GraphQLは何に向いているか
各fieldをクライアントが使っていないことを明示できるので、fieldの利用状況を調べやすい
モニタリングとログ記録
- field レベルでロギングを有効化出来る
- ログレベルも NONE, ERROR, ALL の 3 種類がある
Batching について、 GraphQL の文脈で
Rails × GraphQL だと N+1 問題が難しくなるみたい。他の言語でもあるかもしれない。N+1 が発生する箇所は工夫してコードを書かないけんが、クライアント側で決定できる & endpoint が一つなのでうまくいかない。事前にどんなモデルがどんなモデルを必要とするのかリレーションがわからないから。
Data Loader を使うと schema から生成されたモデルに対して自前で実装した Loader を追加できる。fields が呼び出される時、Loader が実行されるんだろうな。
GraphQLクライアントの技術選定 2023冬
エコシステムが強力である。The Guid を中心としてエコシステム。他にも GraphQL Code Generator, GraphQL Mesh, GramphQL ESLint がある。
Fragment Colocation とは、「コンポーネントのデータ要件を Fragment で定義する」設計思想。Fragment とコンポーネントを同一ファイルに定義することが出来る。
fragment ItemList on Shop { items { name } }
のような fragment と Component を同一ファイルに書いて、useFragment を使って Component にクエリの結果を流し込める。データ要件は各コンポーネントで定義しつつ、データ取得は単一の Query で行えるので
あんまイメージがついてないけど、コンポーネントの階層構造とクエリの階層構造を一致させることが出来るのか?
例えば、Shop Component, Item Component があって親子関係を持っている時、Shop Query と Item Query をそれぞれのコンポーネントで Query を実行せねばいかんかったが、それを一つに出来たという事か?ドキュメントと実装に乖離が生まれないとはどういうことか?
型の自動生成の観点
- Query, Mutation, Fragment の型の自動生成が行えるのか
- Data Masking による安全なデータアクセス
- これがオーバーフェッチに気付けるという事?
- 命名規則の強制
- Strawberry Shake ではどうか
- GraphQL Code Generator とかある
- TypedDocumentNode による型推論
今こそ思い出すGraphQLの特徴
- 必要なフィールドのみ取得
- 不要なフィールドを取得しない
- 不要なフィールドを取得するための無駄な処理が走らない
- 遅延ロード
- 言い換えれば N+1 問題?
- キャッシュを上手く活用する
AWS AppSync入門(GraphQL、AWS CDK)
- Ask for what you need, get exactly that(必要なものだけを得る)
- Get many resources in a single request(複数の情報を一つのリクエストで)
- Describe what’s possible with a type system(何ができるかは型を見ればわかる)
- Evolve your API without versions(バージョン無しでAPIを進化させる)
- Bring your own data and code(好きなデータ、好きな言語で使える)
[AWS Dev Day 2021 A-1] ゼロから始めるAWS AppSync導入の軌跡と振り返り 〜課題も添えて〜
Apollo Server と AWS AppSync の違い。デプロイのフローとか AWS でどんなアーキテクチャを構築していくのかの話。Azure で似たようなアーキテクチャを組みたい時に参考になりそう。
GraphQL 入門 ~ REST と比較しながら学ぶ ~
REST の特徴
- resource 指向での設計である
- ある Web アプリの画面でユーザの体験を実現すると、複数のエンドポイントにアクセスする必要がある
- 表現力の乏しさ
- Status Code とか
ソニー: GraphQLを活用したデータ配信プラットフォームの事例紹介
開発チームのミッションとして
- 素早く
- 最低限の工数でデータ配信を行える仕組みを構築する
- 秩序
- データ配信のインターフェースを統一し、共有を容易にする
- 柔軟に
- クエリやフィルタリングによりクライアントに必要十分なデータを提供する
- 安全に
- データ配信のエンドポイントを統一する事でセキュリティリスクを集約する
GraphQL Gateway とは
- GraphQL Shield
- Apollo Server
- GraphQL Mesh
Hatena Engineer Seminar #14 GraphQL編
GraphQL とは
GraphQL「良さ」・「難しさ」再探訪 〜スタディサプリにおける実例〜 / StudySapuri with GraphQL
スキーマ駆動開発によるフロー効率の向上?スキーマさえ決まり切ってしまえば、サーバー・クライアント別々で実装可能。
resolver って特定のフィールドを返していなければビルド時にエラーが出たりするんだろうか?★
認可の問題は、rails だとエンドポイントごとに認可を行うライブラリが充実している。それが一つのエンドポイントに集約された時、どう工夫をするのかって話になる。
クライアントが任意のクエリを投げられることにより、ネストが深すぎるクエリを投げられる可能性がある 。Data Loader を使ってのチューニング。
Persisted Query ね。
GraphQL を採用するということは依存先を一つ増やすという事
REST を比較して考える事が少なくなったり、開発体験が良くなったりはするだろう
GraphQL と Prisma から考える次のN年を見据えた技術選定
GraphQLにおけるクライアントキャッシュ戦略
- HTTP Header によるキャッシュコントロール
- cache control (ブラウザや共有キャッシュ (Proxy, CDN) で制御するためのもの)
- private: ブラウザのローカルキャッシュのみに保存出来る
- public:
- no-cache
- no-store
- cache control (ブラウザや共有キャッシュ (Proxy, CDN) で制御するためのもの)
ただキャッシュされるだけでなく、どの条件でキャッシュがされるかを正しく理解しておく必要がある -> Strawberry Shake ではどうなっているのか
- レスポンスデータは正規化されてキャッシュに保存される
- 階層構造を持つオブジェクトをフラットにするイメージ
- Query する項目が一つでもキャッシュになければリクエスト
- 細かく項目を取る Query を複数回行うなら、キャッシュヒット率は下がるかもしれない
解決策として - Query の実行順序の工夫 - オブジェクト単位で Query をまとめる - オーバーフェッチが増える - アプリケーション全体で Query を使いまわす - 上の策とセットにしないと意味がない
ページ単位で使用するデータを宣言的に出来る、は Fragment Colocation
と関連しているだろう
- ページを表示するためのコンテンツデータ
- アクションに関わらずページに表示するメタなデータ
- ラベル名とかセレクトボックスの選択肢とか
GraphQLにおけるエラーハンドリングの仕方
上記3つのキーの他にキーを追加したい場合は、extensionsというキーを用意してその中に追加する仕様です。
これが Strawberry Shake でも出来るのかどうか
GraphQL におけるクライアントエラー
- クエリのシンタックスエラー
- クエリのバリデーションエラー
- 型チェックとか
- 認証失敗などの実行時エラー
シンタックスとバリデーションエラーは言語機能で防ぎたい。extension に code を追加してエラー種別をわかりやすくしている。
GraphQLは「オワコン」「流行らない」のか?
GraphQL に対して「オワコン」「流行っている」の定義を行い調査している記事。筆者の結論としては
- 2019年~2022年までは流行っていると言える
- 2023 年からの傾向を見ると今後も流行るとは言いにくい
GraphQL 関連の主な GitHub Repository。さらっと見ておこう。
GraphQLが大注目のグラフAPIとは? 「REST API時代終了」後に注目すべきAPIの新潮流
ここが良くわからない。API ゲートウェイとして GraphQL を使いたくなるパターンの解像度が低い。
Graph API を REST API で提供している場合もある。例えば Microsoft Graph API や SAP Graph など。
全網羅!Spring for GraphQLのエラーハンドリングを徹底攻略!!
Java で GraphQL を使いたい時の事例。C# での参考になりそう。
GraphQLはいつ使うか、RESTとの比較
GraphQLのスキーマ定義やクエリから型定義、自動生成できまっせ
TS で GraphQL を使っている場合、Schema から type
の生成をせねばいかん。それを手でやるのが嫌なので、Code Generator を使って自動生成を行っている。
そもそも手動で型を管理すると何が問題になるんだっけ
- 単純に面倒
- Schema の追加があるたびに
type
を作りたくないじゃん
- Schema の追加があるたびに
- Schema に更新があるたびにそれに追従しないといけない
- 人力でやるというのは常にミスが発生する余地がある
- そのミスにいつ気付けるのか
GraphQL で REST API を作る - 技術的な挑戦と、それを支える文化の話
ユーザ向けには REST API で提供し、内部のリソースをかき集めてくるところは GraphQL になっている。その先の Resolver の実装は gRPC。ユーザ向けに REST を採用しているのは広く使われており慣れ親しんでいるため。より多くのユーザに使ってもらうために意図的に REST にしている。中を GraphQL にしているのは生産性を高めるため。開発組織内での知見が豊富な点と以下の点。
Query の Field Resolver はそのクエリ結果のリソースを返し、Model の Field Resolver はリソース間依存の解決をする
この辺が理解できないのは私のサーバに対する解像度が低いから。
GraphQL スキーマから REST API を生成するようなライブラリがあったの初知り。後半は組織文化の話だった。
GraphQLはサーバーサイド実装のベストプラクティスとなるか
GraphQL を使った設計パターンの種類
- フロントエンド分離
- API Gateway パターン
- Serverless, Microservices
- API Gateway パターン, Serveless/Microservicesパターンの応用としてのgRPC
割とどの記事でも言及されているけど、GraphQL のいいところは
フロントエンド分離ね。確かに、インターフェースを切り離すことでドメインロジックだけに集中してテストが書けそう。ユーザーインターフェースのテストって大変だしね。あとユーザインターフェースの開発には独自の知識が必要だから大変ってのもある。
GraphQL を API Gateway として使うってあるけど、クラウドサービス側で Gateway 関連のサービスが提供されているのにわざわざ GraphQL でやるのは何故だろう。この記事では API Gatewayを利用したときのメリットを享受することが出来ます。
としか書いてなかった。