so I am trying to implement a GQL API using AppSync where I can query a paginated array of items that are stored on a dynamoDB table. My goal is to implemente a forward and backwards pagination system directly on AppSyncJS resolvers
I have the following schema:
type ConnectionPageInfo {
endCursor: String
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
}
type Item {
id: ID!
name: String!
}
type ItemEdge {
node: Item!
}
type ItemPaginatedResponse {
edges: [ItemEdge!]!
pageInfo: ConnectionPageInfo!
}
type Query {
listItems(
first: Int,
last: Int,
after: String,
before: String
): ItemPaginatedResponse
}
This way when calling listItems
query I can send:
first
+ after
params so I can go forwardlast
and before
params so I can navigate backwards.The main issue is that I was expecting the token to be some sort of base64 encoding representation of the pk of the dynamoDB table but it is not. Which makes me not able to generate the startCursor
token. I also tried to obtain the startCursor
or previousToken
token directly from the dynamoDB response but I did not find how
My current AppSyncJS resolver looks like this:
import { Context, util } from '@aws-appsync/utils';
export function request(ctx: Context) {
const organisationId = 'organisation-1'; // this will be a parameter
const { first, last, after, before } = ctx.arguments;
const limit = first ?? last ?? 10;
const nextToken = after ?? before ?? undefined;
const scanIndexForward = !!first;
return {
version: '2017-02-28',
operation: 'Query',
query: {
expression: '#key = :value',
expressionNames: { '#key': 'organisationId' },
expressionValues: { ':value': util.dynamodb.toDynamoDB(organisationId) },
},
limit,
nextToken: nextToken ? nextToken : undefined,
scanIndexForward,
};
}
export function response(ctx: Context) {
if (ctx.result?.error) {
return util.error(ctx.result.error.message, ctx.result.error.type);
}
console.log('obtained result:', ctx.result);
const { items } = ctx.result;
return {
pageInfo: {
endCursor: ctx.result.nextToken,
hasNextPage: !!ctx.result.nextToken,
hasPreviousPage: false, // NOT RELEVANT NOW
startCursor: '', // I DON'T KNOW HOW TO GENERATE THIS BASED ON FIRST ITEM ON THE RESULT ARRAY
},
edges: items.map((item: { id: string; name: string }) => {
return { node: { id: item.id, name: item.name } };
}),
};
}
Is there any way to:
previousToken
on the ctx.result
object?I tried to decode the token returned on nextToken but was not able to.
For anyone who checks this topic. After further investigation and after reaching AWS support it is confirmed that it is not possible to paginate forward + backwards strictly on AppSyncJS dynamoDB resolvers. It is not posible neither to generate nextToken(s) manually for specific items.
There is two possible workarounds for this:
LastEvaluatedKey
and ExclusiveStartKey
PageNumber - Token
relation on a Map/Array so we can resolve this logic somewhere else.