12/8/2020執筆者Rob Richard、Liliana Matos
Rob RichardとLiliana Matosは、1stDibs.comのフロントエンドエンジニアです。彼らは、
@defer
および@stream
ディレクティブの推進者としてGraphQLワーキンググループと協力してきました。
Lee ByronがGraphQL Europe 2016で初めて語って以来、@defer
および @stream
ディレクティブは待望の機能でした。 2020年の大半で、私たちはGraphQLワーキンググループと協力してこの機能を標準化してきました。現在、これはステージ2の提案ですが、さらに前進するために、GraphQLコミュニティにこれらのディレクティブを使用してみてフィードバックを提供することを期待しています。 私たちは、GraphQL.js
と express-graphql
の実験バージョンをリリースしました。 これらは、graphql@experimental-stream-defer
および express-graphql@experimental-stream-defer
としてnpmに公開されています。 この機能に興味のある方は、これらのリリースを試してみて、フィードバック用のissueに結果をお知らせください。 この提案が提供する内容の詳細については、以下をお読みください。
GraphQLのリクエスト/レスポンスモデルの欠点の1つは、GraphQLレスポンスがリクエスト全体の処理が完了するまでクライアントに返されないことです。 ただし、すべてのリクエストデータが同じ重要度を持つとは限らず、ユースケースによっては、アプリケーションがリクエストデータのサブセットに対して動作できる場合があります。 GraphQLサーバーが最も重要なデータを準備ができ次第送信できれば、アプリケーションのインタラクティブまでの時間を短縮できます。 新しい@defer
および @stream
ディレクティブを使用すると、GraphQLサーバーは単一のGraphQLレスポンスから複数のペイロードを返すことで、まさにそれを行うことができます。
@defer
ディレクティブは、フラグメントスプレッドとインラインフラグメントに適用できます。 これは、開発者がクエリの特定部分を即時返却に不可欠ではないとマークするための宣言的な方法です。
@defer
ディレクティブの例を次に示します。
query { person(id: "cGVvcGxlOjE=") { name ...HomeworldFragment @defer(label: "homeworldDefer") }}
fragment HomeworldFragment on Person { homeworld { name }}
ペイロード 1
{ "data": { "person": { "name": "Luke Skywalker" } }, "hasNext": true}
ペイロード 2
{ "label": "homeworldDefer", "path": ["person"], "data": { "homeworld": { "name": "Tatooine" } }, "hasNext": false}
GraphQL実行エンジンが@defer
ディレクティブに遭遇すると、実行をフォークして非同期的にそれらのフィールドの解決を開始します。 遅延ペイロードの準備中も、クライアントは最初のペイロードを受信して処理できます。 これは、遅延データが大きく、ロードに費用がかかり、インタラクティブ性のクリティカルパスにない場合に最も役立ちます。
@defer
と同様に、@stream
ディレクティブも、結果全体が準備される前にクライアントがデータを受信できるようにします。 @stream
はリストフィールドで使用できます。 @stream
ディレクティブの例を次に示します。
query { person(id: "cGVvcGxlOjE=") { name films @stream(initialCount: 2, label: "filmsStream") { title }}
ペイロード 1
{ "data": { "person": { "name": "Luke Skywalker", "films": [ { "title": "A New Hope" }, { "title": "The Empire Strikes Back" } ] } }, "hasNext": true}
ペイロード 2
{ "label": "filmsStream", "path": ["person", "films", 2], "data": { "title": "Return of the Jedi" }, "hasNext": true}
ペイロード 3
{ "label": "filmsStream", "path": ["person", "films", 3], "data": { "title": "Revenge of the Sith" }, "hasNext": false}
GraphQL実行エンジンが@stream
ディレクティブに遭遇すると、initialCount
引数で指定された数のリスト項目を解決します。 残りは非同期的に解決されます。 これは、最初の表示領域にわずかな要素しかレンダリングできないインターフェースに特に役立ちます。 クライアントは、サーバーがデータの残りの部分を解決している間、これらの要素をできるだけ早くレンダリングできます。
GraphQLの仕様ではトランスポートプロトコルを指定していませんが、@defer
/ @stream
を使用したクエリの最も一般的なトランスポートは、チャンク転送エンコーディングを使用したHTTPであると予想されます。 これにより、GraphQLサーバーは標準のHTTP接続を開いたまま、各ペイロードを準備でき次第クライアントにストリーミングできます。 オーバーヘッドが少なく、ブラウザで何十年もサポートされており、ほとんどのインフラストラクチャで簡単に動作します。
これらのディレクティブの詳細については、以下をご覧ください。
– **Rob Richard**、**Liliana Matos**、フロントエンドエンジニアリング、1stDibs.com