GraphQLロゴGraphQL

ページネーション

様々なページネーションモデルにより、クライアントで異なる機能が実現できます

GraphQLの一般的なユースケースは、オブジェクトの集合間の関係を辿ることです。GraphQLでは、これらの関係を公開する方法がいくつかあり、クライアント開発者に様々な機能を提供します。

複数形#

オブジェクト間の接続を公開する最も簡単な方法は、複数形の型を返すフィールドを使用することです。たとえば、R2-D2の友達のリストを取得したい場合は、全員を要求できます

スライシング#

しかし、すぐにクライアントが必要とする追加の動作があることに気付きます。クライアントは、取得する友達の数を指定できることを望むかもしれません。最初の2人だけが必要かもしれません。そのため、次のようなものを公開したいと思うでしょう

{
hero {
name
friends(first: 2) {
name
}
}
}

しかし、最初の2人だけを取得した場合、リストをページングしたい場合もあります。クライアントが最初の2人の友達を取得したら、2番目のリクエストを送信して次の2人の友達を要求したい場合があります。どのようにすれば、その動作を有効にできますか?

ページネーションとエッジ#

ページネーションを行うには、いくつかの方法があります

  • リストの次の2つを要求するために、friends(first:2 offset:2) のようなことができます。
  • 最後に取得した友達の後の次の2つを要求するために、friends(first:2 after:$friendId) のようなことができます。
  • 最後のアイテムからカーソルを取得し、それを使用してページネーションを行うために、friends(first:2 after:$friendCursor) のようなことができます。

一般的に、設計されたものの中で、カーソルベースのページネーションが最も強力であることがわかりました。特にカーソルが不透明な場合、オフセットまたはIDベースのページネーションは、カーソルベースのページネーションを使用して実装できます(カーソルをオフセットまたはIDにすることによって)。また、カーソルを使用すると、将来ページネーションモデルが変更された場合に追加の柔軟性が得られます。カーソルは不透明であり、その形式に依存すべきではないことを思い出させるために、base64エンコードすることをお勧めします。

しかし、それは私たちを問題に導きます。どのようにしてオブジェクトからカーソルを取得するのでしょうか? User タイプにカーソルを配置したくありません。それはオブジェクトではなく、接続のプロパティです。そのため、新しい間接層を導入したい場合があります。 friends フィールドはエッジのリストを提供し、エッジにはカーソルと基になるノードの両方が含まれています

{
hero {
name
friends(first: 2) {
edges {
node {
name
}
cursor
}
}
}
}

エッジの概念は、オブジェクトの1つではなく、エッジに固有の情報がある場合にも役立ちます。たとえば、APIで「友情時間」を公開したい場合、エッジに配置するのが自然な場所です。

リストの終わり、カウント、および接続#

これで、カーソルを使用して接続をページングできますが、接続の終わりに達したことをどのように知るのでしょうか? 空のリストが返されるまでクエリを続ける必要がありますが、追加のリクエストが必要ないように、接続から終わりに達したことを知らせてほしいと思います。同様に、接続自体に関する追加情報を知りたい場合はどうでしょうか?たとえば、R2-D2には合計で何人の友達がいるのでしょうか?

これらの両方の問題を解決するために、friends フィールドは接続オブジェクトを返すことができます。接続オブジェクトには、エッジのフィールドと、その他の情報(合計数や次のページが存在するかどうかなどの情報)が含まれます。そのため、最終的なクエリは次のようになります

{
hero {
name
friends(first: 2) {
totalCount
edges {
node {
name
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
}

このPageInfoオブジェクトには、endCursorstartCursorも含まれる場合があることに注意してください。このように、エッジに含まれる追加情報が必要ない場合は、ページネーションに必要なカーソルがpageInfoから取得されるため、エッジをまったくクエリする必要はありません。これは、接続の使いやすさを向上させる可能性があります。 edgesリストを公開するだけでなく、ノードだけの専用リストを公開して、クライアントに適している場合にエッジの間接層を回避することもできます。

完全な接続モデル#

明らかに、これは複数形を持つだけの元の設計よりも複雑です!しかし、この設計を採用することで、クライアントに多くの機能が解放されました

  • リストをページングする機能。
  • totalCountpageInfoなど、接続自体に関する情報を要求する機能。
  • cursorfriendshipTimeなど、エッジ自体に関する情報を要求する機能。
  • ユーザーは不透明なカーソルを使用するだけなので、バックエンドでのページネーション方法を変更する機能。

これを実際に確認するために、サンプルスキーマには、これらの概念すべてを公開するfriendsConnectionという追加フィールドがあります。サンプルクエリで確認できます。 friendsConnectionへのafterパラメータを削除して、ページネーションがどのように影響を受けるかを確認してください。また、edgesフィールドを接続のヘルパーfriendsフィールドに置き換えてみてください。これにより、クライアントに適している場合、エッジの間接層を追加することなく、友達のリストに直接アクセスできます。

接続仕様#

このパターンの実装の一貫性を確保するために、Relayプロジェクトには、カーソルベースの接続パターンを使用するGraphQL APIを構築するための公式の仕様があります。

続きを読みます →グローバルオブジェクト識別