GraphQL DataLoader の実践的な使い方

DataLoader とは GraphQL におけるデータ取得において内部で N+1 処理になるのを回避するためのツールです。例えば、あるリソース(A)一覧とそれに関連付けられた 1:1 のリソース(B)を一気に要求すること場合、最初のリソース(A)リストをクエリした後に、各レコードに対してリソース(B)を毎回クエリすると遅くなります。リソース(B)に対してそのキーをスタックしていき、まとめてクエリすることで N+1 回を 1+1 回に減らすことができます。この機能をまとめたものが DataLoader です。 実践的な使い方 条件検索について DataLoader はあくまでも Key-value キャッシュ付きストアと考えた方がいいです。GraphQL の検索 Query で条件指定する場合は DataLoader を経由せずに直接行います。但し結果はその後の下階層で再度利用する可能性があるので prime メソッドでキャッシュしておきます。 キーによるレコード検索について マスターリソースに対する場合は、単純に主キーで取得およびキャッシュします。 リレーションリソースに対する場合は、複合キーが cacheKeyFn の処理によってユニークな文字列になるように変換します。サロゲートキーは使いません。 要求したユーザーによって結果が変わる場合 この場合は、リクエストコンテキストに応じて DataLoader インスタンスを生成し付与します。コンテキストを生成するミドルウエア内で、DataLoader インスタンス自体をセットするか、それらインスタンスを生成できるメソッドを提供するといいでしょう。 どのレイヤーのデータを DataLoader で扱うべきか GraphQL の Type とデータベースのレコードスキーマが完全に一致せずに、データの変換が必要となる場合の問題です。基本的にデータベースレイヤーに DataLoader を適用して、GraphQL Type には都度変換する方がいいと考えます。この理由としてリゾルバ周りの変更の影響を受けないことや、 N+1 はそもそもデータベース(ストレージ)への負荷であるからです。 コンテキストから DataLoader をどうモデルに渡すか コンテキストはリゾルバのパラメータとして受け取りますが、DataLoader インスタンスは下位レイヤーのモデル(ロジック層やストレージ層)で使いたいので、そのままストレートにモデルのコンストラクタなどで渡すのが一番だと思います。これに引っ張られて Active-Record パターンは JavaScript ベースでは使いずらいと思います。Ruby on Rails 等だとスレッドに情報をセットして、透過的に扱うことも可能ですが。

2019年6月23日 · Toshimitsu Takahashi

Node.js Koa の RESTful API サーバに GraphQL を導入する

Node.js の HTTP サーバフレームワーク Koa で作られた API サーバに GraphQL 導入する方法です。 簡略化した例として、TodoリストのAPIサーバとして POST /api/todo で新規アイテムを登録し、 GET /api/todo でリストで取得できるもので説明します。同様の操作ができる機能を GraphQL で提供します。 RESTful API サーバの実装状態 koa-router はネストすることが可能なので、 /api は apiRouter として定義し、後で /graphql は別途 graphqlRouter として利用します。 package.json 依存する npm モジュールは以下の通りです。 1 2 3 4 5 6 7 8 9 { "dependencies": { "graphql": "^14.2.1", "koa": "^2.7.0", "koa-bodyparser": "^4.2.1", "koa-graphql": "^0.8.0", "koa-router": "^7.4.0" } } models/todo.js メモリ上の配列でTodoを管理する簡易的なものです。中身は同期処理ですが、より実践的にするため async (Promise) にしています。 ...

2019年4月12日 · Toshimitsu Takahashi