thumbnail

【GraphQL】beforeやafter, first, edgeとは何か?

GraphQL APIで目にするbefore、after、firstやlastといった変数、並びにnodesやedges、cursorやpageInfoの意味について分かりやすく解説します。

【概要】before, after, first, lastとは

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 Cursor Connectionsという仕様の概要について理解する
  • カーソルを利用したページングについて理解する
  • Relay Cursor Connectionsで使われている値について順次理解する
    (①node/edge → ②connection/ pageInfo → ③ before/ after/ first/ last)

Relay Cursor Connectionsって何?

Relayとは

まず「Relay」とは、Facebookが開発したGraphQLのフレームワークです。その「Relay」で使われているページングの実装の仕様が「Relay Cursor Connections」です。

Cursor Connectionsとは

ページングの方法は大きく分けて「①オフセットを利用する方法」「②カーソルを利用する方法」の2つがあります。このうち、②の「カーソルを利用する方法」が表題の「Cursor Connections」にあたります。(オフセットとカーソルについては次節で説明します。)

以上から、「Relay Cursor Connections」とは、「Relay」というフレームワークで使われている「カーソルを利用したページング」に関する仕様ということになります。この仕様に則ってフェッチされるデータは、実データにページング情報が付与されています。

続いて、「オフセット」と「カーソル」について次節で軽く説明します。

オフセット、カーソルによるページングの違い

①オフセットを利用したページング

オフセットとは、「最初から数えて何番目か」を表す値です。オフセットを利用したページングではオフセットと取得件数を指定します。つまりオフセット(offset)がNで取得件数(limit)がMのとき、「最初から数えてN+1番目の値から、M個データを持ってくる」ような実装となります。

この方法は実装が楽ですが、データ取得時の通信が大きくなったり、データ更新時の整合性に少し問題があります。

②カーソルを利用したページング

カーソル(cursor)とは、それぞれのデータが持つポインタのようなものです。つまり、すべてのデータに「自分の住所、場所」を表す文字列をデータとともに持たせます。そしてcursorを利用したページングでは「カーソルAのデータの後ろのデータをM個持ってくる」ような実装となります。

GraphQLの公式ドキュメントでは、カーソルを利用したページングが最もパワフルだと紹介されています。

変数の意味を知る

nodeとedge

node(ノード)とedge(エッジ)は数学のグラフ理論に基づいたもので、そもそもGraphQL自体がこのグラフに則ったものです。ここでグラフ理論の~と深堀するのではなく、Relay Cursor Connectionsの概要に必要な話に絞って解説します。

node

nodeは、typeで定義するデータのまとまりです。本来フェッチしたいデータを表します。

# nodes
type User {
  id: ID!
  name: String!
  post: [Post]
}

#nodes
type Post {
  id: ID!
  title: String!
  body: String!
  userId: ID!
}

edge

edgeはのnode(データ)とcursor(カーソル、住所)の2つからなります。
カーソルの実態はbase64でエンコードされたただの文字列で、それぞれのノードの住所を表現しています。

# edge
type UserEdge {
  node: User
  cursor: String!
}

connectionとpageInfo

続いてconnectionとpageInfoの説明に入ります。

connection

前節のedgeの集まりを配列edgesとし、これにページングの情報pageInfo(すぐ後で説明)を加えたものをconnectionといいます。

# connection
type UserConnection {
  edges: [UserEdge]
  pageInfo: PageInfo!
}

このconnectionこそが、Relay Cursor Connectionsでフェッチしたときに返されるデータ一式となります。
つまり、実データ(node)にカーソル(cursor)+ページング情報(pageInfo)が付与されたデータがフェッチされます。

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

before、afterはカーソル、firstとlastはデータの取得件数を表します。

これら4つの値はデータ取得時のクエリパラメータとして利用します。
このクエリパラメータでクエリを発行すると、前節のconnection(実データ+カーソル+ページング情報)が返ってきます。

type Query {
  users(first: Int, after: String, last: Int, before: String): UserConnection!
}

しかし、この4つのパラメータを同時に使うことはありません。
クエリパラメータは、以下2パターンに分けて利用します。

  • ①順方向(1ページ目→2ページ目等)のページングでは「afterとfirst」
  • ②逆方向(3ページ目→2ページ目等)のページングでは「beforeとlast」

続いて詳しい使い方について説明します。

①順方向のページング

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」