色んな事を書く

シンプルさを極めたエンジニアになりたい

GraphQL の色んな記事まとめ

自分用に GraphQL を学んだ際に参考にした記事たちとその内容をまとめて残しておきます。

GraphQLスキーマ設計の勘所

  • GraphQL はプロトコルなので、スキーマの設計は後方互換性が必要
  • クライアントサーバ双方の都合を理解して設計をする必要がある
    • クライアント・サーバが別チームで開発をしていると、スキーマの合意が結構大変だったりする?
  • GraphQL を使っていても、ID 参照をしていれば複数回のリクエストが飛んでしまう
    • 例えば User, Company というスキーマがあり、User は CompanyId を持っているとする。この時に query で user { companyId } みたいなことをしてしまうと、user を取った後に companyId を使ったリクエストが必要になる
    • user { company { name } } といったグラフ構造で query を記述する必要がある
  • Field 単位のリゾルバで無駄なリソースの取得を回避しよう
    • User { company { name } } を取得するような operation のリゾルバでは Company Repository を使ってデータを取る必要がある
    • そのリゾルバを User { name } みたいな Company を不要とする query にも使ってしまうと、余計なコストがかかるので避けよう
  • mutation は専用の Payload を返すようにする
    • updateUser みたいな mutation に対し User そのものを返すようにしていると、いつか壊れるかもしれない
    • 専用の type を作って拡張しやすくしていこう
      • type 同士の依存関係をなるべく減らそう
  • ビジネスロジックも type で表していこう
    • User { isAdalt } で age >= 20 の時のみ true となるロジックも積極的に Schema 定義する
    • それを必要とする場合は専用の Resolver を呼び出せばよい
  • クライアント側の決定性のためにカーソル・ページネーション
    • 決定性とはクライアント側でレスポンスの内容を決定できる性質のこと

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 -> 商品データ

実装パターンとして

  1. 内部 API の結果を成型して外部 API へのリクエストを作る
  2. 内部 API から外部 API を呼び出す というのが考えられる

抽選データだけ欲しいのに商品データまで取ってしまう (無駄に外部 API を呼び出す) という課題がある。... Resolver を工夫すればええんとちゃうんかと思ったが -> 実際に商品に対する Resolver を作って解決をしていた

認証や N+1 はキャパオーバーだから後回し

GraphQL 成熟度モデルの紹介と、プロダクトに当てはめた事例 / GraphQL maturity model

  1. サーバの GraphQL サポート
  2. Playground の提供
    • Playground はスキーマを確認したりクエリを実行してみるなどを行える環境の総称
    • Playground を実現するために Apollo Sandbox や GraphiQL がある
  3. GraphQL スキーマと言語の型システムの統合
    • フロントもバックエンドもスキーマをベースにして型システムを導入しようね
    • この辺りに Roslyn のコード生成の話が入ってくる
  4. スキーマのデフォルト値を nullable にする
    • これによりバックエンドでの例外を null として表現出来るようになる
      • フロントでは null のハンドリングだけやればアプリは継続して利用できる
    • null はレスポンスデータの破壊的変更にも対応している
      • モバイルは破壊的変更の対応が難しい。ストアにアップして~とかが時間かかる
      • Web はフロント・バックどちらもコントローラブル。デプロイ時の工夫でどうとでもなる
  5. Node 仕様の実装
    • ここで分かったのは Node 仕様に準拠するとグローバル ID を持つという事
  6. フロントエンドで正規化されたキャッシュの利用
    • Document Caching というキャッシュのアルゴリズムがある。mutation のタイミングで関連する query を全部再実行してくれるんですって 7, Relay Connections
    • リストのモデリングの話
    • 自動コード生成に組み込めるかもしれない
  7. Fragment を利用した UI データの定義
  8. 複数の Fragment をまとめて取得
    • Razor Component はこの辺りに関わってきそう
  9. @defer と @stream のサポート
  10. UX を向上させるための仕組む
  11. 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 とは

  • API のためのクエリ言語とクエリに応じたデータを返すランタイム
  • スキーマはランタイムがどんなデータを返せるか記述したもの

GraphQL「良さ」・「難しさ」再探訪 〜スタディサプリにおける実例〜 / StudySapuri with GraphQL

スキーマ駆動開発によるフロー効率の向上?スキーマさえ決まり切ってしまえば、サーバー・クライアント別々で実装可能。

resolver って特定のフィールドを返していなければビルド時にエラーが出たりするんだろうか?★

認可の問題は、rails だとエンドポイントごとに認可を行うライブラリが充実している。それが一つのエンドポイントに集約された時、どう工夫をするのかって話になる。

クライアントが任意のクエリを投げられることにより、ネストが深すぎるクエリを投げられる可能性がある 。Data Loader を使ってのチューニング。

Persisted Query ね。

GraphQL を採用するということは依存先を一つ増やすという事

REST を比較して考える事が少なくなったり、開発体験が良くなったりはするだろう

GraphQL と Prisma から考える次のN年を見据えた技術選定

GraphQLにおけるクライアントキャッシュ戦略

REST API でのキャッシュ

  • HTTP Header によるキャッシュコントロール
    • cache control (ブラウザや共有キャッシュ (Proxy, CDN) で制御するためのもの)
      • private: ブラウザのローカルキャッシュのみに保存出来る
      • public:
      • no-cache
      • no-store

ただキャッシュされるだけでなく、どの条件でキャッシュがされるかを正しく理解しておく必要がある -> 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ゲートウェイの時代も終焉を迎えつつある。

ここが良くわからない。API ゲートウェイとして GraphQL を使いたくなるパターンの解像度が低い。

Graph APIREST API で提供している場合もある。例えば Microsoft Graph API や SAP Graph など。

全網羅!Spring for GraphQLのエラーハンドリングを徹底攻略!!

Java で GraphQL を使いたい時の事例。C# での参考になりそう。

GraphQLはいつ使うか、RESTとの比較

GraphQLのスキーマ定義やクエリから型定義、自動生成できまっせ

TS で GraphQL を使っている場合、Schema から type の生成をせねばいかん。それを手でやるのが嫌なので、Code Generator を使って自動生成を行っている。

そもそも手動で型を管理すると何が問題になるんだっけ

  • 単純に面倒
    • Schema の追加があるたびに type を作りたくないじゃん
  • 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を利用したときのメリットを享受することが出来ます。としか書いてなかった。