Duas estratégias: baseada em offset (limit/offset) e baseada em cursor. O GraphQL não tem paginação embutida, mas o padrão da comunidade é a especificação Relay Connection, que formaliza a paginação por cursor.
Duas estratégias: baseada em offset (limit/offset) e baseada em cursor. O GraphQL não tem paginação embutida, mas o padrão da comunidade é a especificação Relay Connection, que formaliza a paginação por cursor.
items(limit: 10, offset: 20)) é simples, mas quebra com dados em tempo real: se uma linha é inserida enquanto o usuário pagina, os itens se deslocam e você vê duplicatas ou lacunas. Também fica lento em offsets profundos (o banco ainda varre as linhas puladas).Uma connection envolve a lista em edges (cada um com um cursor e um node) mais pageInfo:
type Query {
posts(first: Int!, after: String): PostConnection! # first = page size, after = cursor
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
cursor: String! # opaque token for THIS node's position
node: Post! # the actual item
}
type PageInfo {
endCursor: String # feed this back as 'after' for the next page
hasNextPage: Boolean! # so the client knows when to stop
}
// resolver: fetch ONE extra row to compute hasNextPage cheaply
const rows = await db.posts.find({ after: args.after, limit: args.first + 1 });
const hasNextPage = rows.length > args.first;
const page = rows.slice(0, args.first);
return {
edges: page.map((p) => ({ node: p, cursor: encodeCursor(p.id) })),
pageInfo: { endCursor: page.at(-1) && encodeCursor(page.at(-1).id), hasNextPage },
};
O cursor é opaco — geralmente um base64 da chave de ordenação — então os clientes o tratam como um token, não como um número.
Escolher offset vs. cursor mostra que você entende consistência sob escritas concorrentes e desempenho em páginas profundas. Conhecer o formato da Relay connection importa porque os clientes Apollo/Relay têm tratamento de cache embutido para ele.
Uma biblioteca de perguntas de entrevista de TI com respostas detalhadas — de Júnior a Sênior.
Doar