1001Ferramentas
📃 Geradores

Gerador de resposta paginada JSON

Gera JSON com estrutura de paginação fake (page, pageSize, total, items) para mockar API REST.

JSON paginado mock: design de API do offset/limit ao cursor

Paginação é o problema ergonômico mais comum em design de APIs REST e GraphQL, e também um dos mais fáceis de errar. Um gerador de JSON paginado mock permite que times de front-end, devs mobile e autores de SDK construam telas, feeds com scroll infinito e tabelas antes do backend estar pronto, com envelopes de resposta que casam com o contrato de produção. Também serve como artefato didático: uma única ferramenta que emite variantes offset/limit, cursor, keyset e timestamp torna os trade-offs concretos e visíveis lado a lado.

Os quatro padrões canônicos são fáceis de reconhecer. Offset/limit usa ?page=2&limit=20 ou ?offset=20&limit=20; simples, permite pular para qualquer página, mas instável quando linhas são inseridas entre requisições e lento em tabelas grandes porque o banco ainda precisa contar e descartar as primeiras OFFSET linhas. Cursor-based usa um token opaco como ?cursor=eyJpZCI6MTAwfQ==; estável diante de inserções, rápido mesmo em bilhões de linhas, mas você não consegue saltar para a "página 50". Keyset (também chamado seek) expõe a chave de ordenação direto — ?after_id=100&limit=20 — e é o que a maioria dos cursores decodifica internamente. Timestamp-based, ?since=2024-01-01T00:00:00Z, é o ajuste natural para feeds de atividade e webhooks.

Envelopes de resposta e padrões de mercado

Uma resposta paginada quase sempre vem envolta em um envelope com duas partes: um array data com os itens e um objeto meta descrevendo a página. Campos comuns são current_page, per_page, total, total_pages, next_url e prev_url. A especificação JSON:API padroniza isso com um objeto links contendo URLs self, first, last, prev e next — um design HATEOAS em que o cliente segue links em vez de montá-los. GraphQL Relay usa connection + edges + pageInfo com endCursor e hasNextPage; Stripe retorna has_more e um auto_paging_iter() no SDK; GitHub coloca os dados de paginação no header HTTP Link em vez do corpo.

{
  "data": [{ "id": 21, "name": "Item 21" }],
  "meta": {
    "current_page": 2,
    "per_page": 20,
    "total": 137,
    "total_pages": 7
  },
  "links": {
    "first": "/items?page=1&limit=20",
    "prev":  "/items?page=1&limit=20",
    "next":  "/items?page=3&limit=20",
    "last":  "/items?page=7&limit=20"
  }
}

Paginação por cursor em detalhe

Cursores opacos costumam ser JSON em base64 contendo a chave de ordenação e o id do último item retornado, para o servidor disparar uma query WHERE (sort_key, id) > (last_sort, last_id) que atinge um índice. A opacidade importa: se os clientes aprenderem o formato, vão adulterá-lo, e mudar o schema depois quebra todo cursor cacheado por aí. Sempre inclua um byte de versão. Cursores são o default certo para feeds infinitos, logs de atividade, transações e qualquer endpoint apoiado em uma tabela que cresce continuamente; offset/limit serve para tabelas administrativas pequenas e resultados de busca em que "página 12" tem significado.

Tamanhos de página, limites e edge cases

Defaults sensatos: tamanho de página padrão 25, máximo 100, rejeite qualquer coisa maior com HTTP 400. Sempre documente o teto. Teste os edge cases que seu front vai bater: resultado vazio, resultado com exatamente limit itens (off-by-one na lógica de "tem próxima página?"), última página, requisição além da última página (retornar data vazia, não 404) e inserções concorrentes (cursor permanece estável, offset desloca). Um gerador mock que deixa você configurar total, per_page e current_page independentemente é a forma mais rápida de cobrir os quatro em testes de componente.

Perguntas frequentes

Cursor ou offset? Cursor para feeds infinitos, tabelas grandes, dados append-only e qualquer caso sensível a performance. Offset para listas administrativas pequenas, resultados de busca e qualquer cenário em que o usuário se beneficia de pular para uma página específica.

Que tamanho de página usar? Padrão 25, permita de 1 a 100, rejeite o resto. Cliente mobile costuma querer 20; exportações de dados querem 100.

Qual envelope é o padrão? Não existe um vencedor único. JSON:API é o mais prescritivo; o padrão estilo Stripe (data + has_more) é o mais copiado por APIs SaaS; o Link header do GitHub é o mais limpo mas o menos descobrível para quem consome via SDK.

Preciso retornar o total? Nem sempre. Devolver total exige uma segunda query (SELECT COUNT(*)) que pode dominar o tempo de resposta. Para feeds infinitos, has_more basta. Para tabelas paginadas que mostram "1-20 de 137", a contagem é inevitável.

Ferramentas Relacionadas