
ブログをNext.js14(App Router)でリファクタリングしました
GraphQL APIで目にするbefore、after、firstやlastといった変数、並びにnodesやedges、cursorやpageInfoの意味について分かりやすく解説します。
目次
before、after、firstやlast、nodesやedgesといった値は、GraphQLが元々備えている値、機能や仕様ではありません。「Relay Cursor Connections」という、”ページング(ページ送り)”を効率的に行う方法に従って実装されたAPIだけが備えているものです。GithubのGraphQL APIやWordPressのWPGraphQLがこれに当たります。
「Relay Cursor Connections」に従って実装されたAPIは、「ページ送り」や「必要な件数だけのデータの取得」が効率よく出来るようになります。自分で0から実装する場合も、この仕様に従って実装する必要があります。そしてこの「Relay Cursor Connections」でbeforeやafter、firstやnodesを使うように決められているのです。
ではbefore, after, first, lastやnodes, edgesはどういう意味なのでしょうか。
順を追って説明していきます。
まず「Relay」とは、Facebookが開発したGraphQLのフレームワークです。その「Relay」で使われているページングの実装の仕様が「Relay Cursor Connections」です。
ページングの方法は大きく分けて「①オフセットを利用する方法」と「②カーソルを利用する方法」の2つがあります。このうち、②の「カーソルを利用する方法」が表題の「Cursor Connections」にあたります。(オフセットとカーソルについては次節で説明します。)
以上から、「Relay Cursor Connections」とは、「Relay」というフレームワークで使われている「カーソルを利用したページング」に関する仕様ということになります。この仕様に則ってフェッチされるデータは、実データにページング情報が付与されています。
続いて、「オフセット」と「カーソル」について次節で軽く説明します。
オフセットとは、「最初から数えて何番目か」を表す値です。オフセットを利用したページングではオフセットと取得件数を指定します。つまりオフセット(offset)がNで取得件数(limit)がMのとき、「最初から数えてN+1番目の値から、M個データを持ってくる」ような実装となります。
この方法は実装が楽ですが、データ取得時の通信が大きくなったり、データ更新時の整合性に少し問題があります。
カーソル(cursor)とは、それぞれのデータが持つポインタのようなものです。つまり、すべてのデータに「自分の住所、場所」を表す文字列をデータとともに持たせます。そしてcursorを利用したページングでは「カーソルAのデータの後ろのデータをM個持ってくる」ような実装となります。
GraphQLの公式ドキュメントでは、カーソルを利用したページングが最もパワフルだと紹介されています。
node(ノード)とedge(エッジ)は数学のグラフ理論に基づいたもので、そもそもGraphQL自体がこのグラフに則ったものです。ここでグラフ理論の~と深堀するのではなく、Relay Cursor Connectionsの概要に必要な話に絞って解説します。
nodeは、typeで定義するデータのまとまりです。本来フェッチしたいデータを表します。
# nodes
type User {
id: ID!
name: String!
post: [Post]
}
#nodes
type Post {
id: ID!
title: String!
body: String!
userId: ID!
}
edgeはのnode(データ)とcursor(カーソル、住所)の2つからなります。
カーソルの実態はbase64でエンコードされたただの文字列で、それぞれのノードの住所を表現しています。
# edge
type UserEdge {
node: User
cursor: String!
}
続いてconnectionとpageInfoの説明に入ります。
前節のedgeの集まりを配列edgesとし、これにページングの情報pageInfo(すぐ後で説明)を加えたものをconnectionといいます。
# connection
type UserConnection {
edges: [UserEdge]
pageInfo: PageInfo!
}
このconnectionこそが、Relay Cursor Connectionsでフェッチしたときに返されるデータ一式となります。
つまり、実データ(node)にカーソル(cursor)+ページング情報(pageInfo)が付与されたデータがフェッチされます。
pageInfoは現在のページの
の4つのプロパティを持ちます。
# pageinfo
type PageInfo {
startCursor: String #1
endCursor: String #2
hasNextPage: Boolean! #3
hadPreviousPage: Boolean! #4
}
ページが複数ある時、
1ページ目は、次ページがあり「hasNextPage: true」前ページがないので「hadPreviousPage: false」、
最後のページなら逆に「hasNextPage: false」「hadPreviousPage: true」、
途中のページならどちらもあるので「hasNextPage: true」「hadPreviousPage: true」
となります。
before、afterはカーソル、firstとlastはデータの取得件数を表します。
これら4つの値はデータ取得時のクエリパラメータとして利用します。
このクエリパラメータでクエリを発行すると、前節のconnection(実データ+カーソル+ページング情報)が返ってきます。
type Query {
users(first: Int, after: String, last: Int, before: String): UserConnection!
}
しかし、この4つのパラメータを同時に使うことはありません。
クエリパラメータは、以下2パターンに分けて利用します。
続いて詳しい使い方について説明します。
afterで指定したカーソル位置の次のデータから、first個数のデータを取得するという意味になります。
query UserQuery {
users(first: 10, after: "rgainrgorao")
}
beforeで指定したカーソル位置の前のデータから、last個のデータを取得するという意味です。
query UserQuery {
users(last: 10, before: "agrinaornga")
}
以上がRelay Cursor Connectionsの説明となります。
Relay Cursor Connectionsで使われている変数の説明を行いました。
ネットで検索すると「GraphqQLでページングがしたい→Relay Cursor Connectionsにたどり着く→beforeやafterを知る」という順が前提の記事ばかりであったので、逆に「nodesとかedge, before, afterって何?→Relay Cursor Connectionsってのがあるのか→ページングの仕様なんだ」と知るような記事にしました。
・Relay Cursor Connectionのより具体的な説明
・GraphQL公式ドキュメントより「Pagination and Edges」
関連記事
最新の記事
カテゴリー一覧
アーカイブ