- splitting list into chunks
- beware: “page” is historical term where chunks were used for book-like pages, think Google
- allows client to fetch only part of list, resume where left off
- assume sorted list, list adds / deletes items only at ends, e.g. sorted by creation date of item
- beware: can not add / delete data in middle of list, otherwise duplicate / skipped chunks ❗️
Offset
- offset from beginning (or end) of list
{
users(first: 2, offset: 2) {
name
}
}
- problem: can only add data to opposite end of list from which offset, otherwise duplicate / skipped chunks
- use if list adds / deletes items only to / from opposite end of offset, never other end or middle
Cursor
- pointer to item in list
- uses unique property of item that doesn’t change, e.g.
id
field
- make cursor opaque to not leak implementation details, otherwise can’t change in future, e.g. base64 encode of
id
field
{
users(first: 2, after: $userCursor) {
name
}
}
- needs to communicate cursor, can’t be field of list object since meta property of connection
- need to introduce intermediate object in hierarchy, corresponds to relationship between two nodes in graph
- beware: pagination is “ugly”, because prevents that all objects correspond to nodes in graph ❗️
- “connection” object, contains
pageInfo
object with cursor and last page flag
- connection can have metadata fields, e.g.
totalCount
of connections
{
usersConnection(first: 2, after: $userCursor) {
totalCount
users {
name
}
pageInfo {
endCursor
hasNextPage
}
}
- need to introduce another intermediate object because wants cursor for individual item, allows to continue paging through list from any item instead of only from end of chunk
- edges list, each edge contains own cursor
- edge can have metadata fields, e.g. date
since
edge exists
- beware: final object is singular
node
object, since edge list is isomorph to object list
{
usersConnection(first: 2, after: $userCursor) {
totalCount
edges {
node {
name
}
cursor
since
}
pageInfo {
endCursor
hasNextPage
}
}
- can still provide list object on connection object as convenience for when doesn’t need cursor or metadata of each edge
{
usersConnection(first: 2, after: $userCursor) {
totalCount
edges {
node {
name
}
cursor
since
}
users {
name
}
pageInfo {
endCursor
hasNextPage
}
}
type Query {
usersConnection(
first: Int,
last: Int,
after: String,
before: String
): UsersConnection
}
type UsersConnection {
totalCount: Int
edges: [UsersEdge]
users: [User]
pageInfo: PageInfo!
}
type UsersEdge {
node: User
cursor: String!
since: Date
}
- beware: could also name
users
what here is usersConnection
and nodes
what here is users
, e.g. GitHub ❗️
Resources