GraphQL pagination
Riseact's GraphQL queries that return lists use cursor-based pagination. This approach is stable against items being inserted or removed while navigating, unlike offset pagination.
Response structure
Every paginated query returns a Connection:
type Connection {
pageInfo: PageInfo!
edges: [Edge!]!
}
type Edge {
cursor: String!
node: <EntityType>!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
total: Int!
}
The total field always contains the overall number of results (ignoring pagination), useful for computing the number of pages.
Pagination input
input PaginationInput {
first: Int # how many items to take from the head
last: Int # how many items to take from the tail
after: String # cursor: take the items after this one
before: String # cursor: take the items before this one
}
Default size: 25 items, if both first and last are omitted.
You cannot use first and last in the same request.
Forward navigation
To page through the results from the first to the last page, use first + after.
First page:
query {
donations(pagination: { first: 20 }) {
pageInfo {
hasNextPage
endCursor
total
}
edges {
cursor
node {
id
state
amount
}
}
}
}
Next page (using endCursor from the previous response):
query {
donations(pagination: { first: 20, after: "Y3Vyc29yOnYxOjIwMjMtMDgtMTd8MTIz" }) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
id
state
amount
}
}
}
}
Backward navigation
To page from the end toward the beginning, use last + before.
query {
donations(pagination: { last: 20, before: "Y3Vyc29yOnYxOjIwMjMtMDgtMTd8MTIz" }) {
pageInfo {
hasPreviousPage
startCursor
}
edges {
node {
id
state
amount
}
}
}
}
How cursors work
Cursors are opaque strings encoded in Base64. They encode the values of the item's ordering fields (e.g. payment_date|id). They must not be interpreted or built manually: always use the cursors returned by startCursor / endCursor / edges[*].cursor.
Fetching all items
To download all results without paging, iterate using hasNextPage and endCursor:
async function fetchAll(client) {
let after = null;
const results = [];
do {
const { data } = await client.query({
query: DONATIONS_QUERY,
variables: { pagination: { first: 100, after } },
});
results.push(...data.donations.edges.map(e => e.node));
after = data.donations.pageInfo.hasNextPage
? data.donations.pageInfo.endCursor
: null;
} while (after);
return results;
}
Queries that support pagination
The following queries accept pagination: PaginationInput:
donationspaymentssupporterscampaignscheckoutsactivities