Support Relay connections spec
Closed this issue · 5 comments
EDIT: I mistakenly assumed that Fauna's GraphQL pagination fields had a 1:1 correspondence with FQL's Pagination
function arguments, and my original comments were based off of my experience with Fauna's GraphQL pagination. I see now that Pagination
supports specifying a cursor by ref, which is very similar to how Relay connection cursors work.
Many GraphQL clients and servers support Relay-style connections as a solution for pagination:
It would be really great if faunadb-graphql-lib
also supported these connections, especially since Fauna's own GraphQL schema doesn't support them.
FQL's Paginate
and Relay connections offer cursor-based pagination. The biggest difference is in how cursors are used:
In Relay connections, the cursor encodes an item's position within an array. You pass the cursor toafter
and provide how many items you want withfirst
for forward pagination (e.g.,after: ..., first: 10
gets the first 10 results after...
) or you usebefore
andlast
for backward pagination (e.g.,before: ..., last: 10
gets the last 10 results after...
).In FQLPaginate
, the cursor encodes a position before or after an item, which implies directionality. You pass the cursor as thecursor
parameter and the quantity you want to thesize
parameter (e.g.,Paginate(input, {cursor: ..., size: 10})
gets the first or last 10 items before or after...
, and the direction depends on the cursor itself).
Given the differences between the two approaches, any implementation would have to create its own cursors rather than rely on those provided by Fauna.
I think that a good place to start for generating cursors might be a base64 encoded version of the ID:
Especially if the cursors are opaque, either offset or ID-based pagination can be implemented using cursor-based pagination (by making the cursor the offset or the ID), and using cursors gives additional flexibility if the pagination model changes in the future. As a reminder that the cursors are opaque and that their format should not be relied upon, we suggest base64 encoding them.
However, I don't know whether this is too naive. For example, how unique are Fauna ID's? Does the documentation for the NewId
function apply to all ID's?
This NewId function produces a unique number. This number is guaranteed to be unique across the entire cluster and once generated is never generated a second time.
It may actually be possible to use connectionFromPromisedArraySlice
from graphql-relay
to implement connections without any further work to the AST transform. I will investigate.
Since faunas cursors are based on the shape of the underlying index (so could be an array with ref(s), strings, numbers etc.) the current approach has worked well as a generic solution for us.
Yes, looks like you're right. The queries get translated to an on-the-wire JSON representation by faunadb-js
that represents the shape of the cursor ref. GraphQLFaunaCursorType
is able to serialize and deserialize this JSON representation.
I did see in the Fauna Slack that the team hasn't committed to any particular wire protocol for transmitting queries back to Fauna, so it's possible that the underlying JSON structure will change in the future. If they move to a binary protocol, then the current approach in GraphQLFaunaCursorType
might not work, depending on the driver library's implementation. But let's not worry about that 🙂.
Anyway, I wanted to say that I was able to implement Relay connections using this library. My general approach is:
- Modify
astToFaunaQuery
to allow leaf nodes to accessfql
queries. (See issue #3.) - For each connection, create a custom connection and edge class using
GraphQLFaunaCursorType
for thecursor
field. - Create a generic
PageInfo
class usingGraphQLFaunaCursorType
for thestartCursor
andendCursor
fields. - Create FQL queries in the
fql
properties of each relevant field to get the cursors, etc.
I'm currently using this approach in my fork. I'll submit a PR for issue #3 and possibly create a generic solution for Relay connections once this project goes officially public. Closing this issue for now.