GraphQL Pagination: Opaque Cursors
Why use an opaque cursor?
We want to let the cursor be a cursor, and nothing more. Rather than using a createdAt
date as the cursor value, we can use a base64 encoded string (generated from the createdAt
date). This serves as a reminder to the client to not rely on the cursor value to be of any particular type or have any particular meaning other than being a marker to identify the last item in the returned page. The client then passes this string as the cursor argument in the next page query to tell the API, “here’s where I left off last time, get me the next X number of items.”
Implementation
We need to to a few key things:
Create helper functions that encode and decode a string to and from base64.
toCursorHash
This is how we serialize any value with meaning into a “meaningless” cursor value
fromCursorHash
The corresponding function to decode the cursor hash and give it meaning again, so our resolver can use it in the database query.
Encode the
createdAt
date of the last retrieved node before putting it into thepageInfo
object as theendCursor
.Decode the opaque cursor value (back into a meaningful
createdAt
date) before using it in our resolver’s query to the database.Update our schema so that the
endCursor
field on thePageInfo
type returns aString
instead of aDate
Here’s what each of these looks like:
Helper functions
Resolver
Schema
Does it work?
Running the posts query in GraphQL Playground now returns an opaque string as the endCursor
in the pageInfo
object. We can use that string as the cursor
argument in our next query.