Conceitos

Paginação

Como percorrer uma listagem por páginas: o cursor, o tamanho e o ciclo certo.

As listagens devolvem uma página de cada vez, por cursor: em vez de «página 3», a resposta diz a partir de onde continuar. Isto mantém a listagem estável mesmo que apareçam registos novos enquanto a percorre.

ParâmetroSentido
tamanhoQuantos itens por página, de 1 a 200 (por omissão 50). Fora do intervalo: 400 PEDIDO_INVALIDO.
cursorO proximoCursor da página anterior. Omita-o para a primeira página. É opaco: não o construa nem o altere (um cursor inventado dá 400).

Uma página de 2 clientes

Pedido
curl 'https://<endereço-da-API>/api/clientes?tamanho=2' \
  -H 'X-Api-Key: assw_v1_<chave>'
Pedido
const resposta = await fetch('https://<endereço-da-API>/api/clientes?tamanho=2', {
  method: 'GET',
  headers: {
    "X-Api-Key": "assw_v1_<chave>"
  },
})
const dados = await resposta.json()
Pedido
import requests

resposta = requests.get(
    'https://<endereço-da-API>/api/clientes?tamanho=2',
    headers={
        'X-Api-Key': 'assw_v1_<chave>'
    },
)
dados = resposta.json()
Pedido
using var cliente = new HttpClient { BaseAddress = new Uri("https://<endereço-da-API>") };
using var pedido = new HttpRequestMessage(HttpMethod.Get, "/api/clientes?tamanho=2");
pedido.Headers.Add("X-Api-Key", "assw_v1_<chave>");
using var resposta = await cliente.SendAsync(pedido);
var texto = await resposta.Content.ReadAsStringAsync();

200 OK Resposta

Resposta
content-type: application/json; charset=utf-8
x-mucanda-api-version: 1

{
  "itens": [
    {
      "id": "01a12201-fa2a-7eec-8bcb-2f0b5e02bb8e",
      "nome": "Ana Beatriz Kiala",
      "numeroContribuinte": "004512987LA041",
      "telefone": "925112233",
      "especial": false,
      "saldoAtual": 0,
      "isProtegido": false
    },
    {
      "id": "01a12201-fa49-7e89-af00-dde77cab4010",
      "nome": "Cantina do Mercado Velho",
      "numeroContribuinte": "5417220318",
      "telefone": "928667788",
      "especial": false,
      "saldoAtual": 0,
      "isProtegido": false
    }
  ],
  "proximoCursor": "Q2FudGluYSBkbyBNZXJjYWRvIFZlbGhvIDAxYTEyMjAxLWZhNDktN2U4OS1hZjAwLWRkZTc3Y2FiNDAxMA=="
}

A resposta tem sempre itens e proximoCursor. Continue enquanto proximoCursor não for null. Uma página que vem cheia traz sempre cursor, mesmo que não haja mais registos: a página seguinte pode vir vazia. Por isso o ciclo termina quando o cursor é null ou a página vem vazia.

JavaScript
async function todosOsClientes() {
  const clientes = []
  let cursor = null
  do {
    const url = new URL('https://<endereço-da-API>/api/clientes')
    url.searchParams.set('tamanho', '200')
    if (cursor) url.searchParams.set('cursor', cursor)

    const resposta = await fetch(url, { headers: { 'X-Api-Key': process.env.MUCANDA_API_KEY } })
    if (!resposta.ok) throw new Error(`Erro ${resposta.status}`)
    const pagina = await resposta.json()

    clientes.push(...pagina.itens)
    cursor = pagina.itens.length === 0 ? null : pagina.proximoCursor
  } while (cursor)
  return clientes
}
Python
import os
import requests

def todos_os_clientes():
    clientes, cursor = [], None
    while True:
        params = {'tamanho': 200}
        if cursor:
            params['cursor'] = cursor
        r = requests.get('https://<endereço-da-API>/api/clientes',
                         params=params, headers={'X-Api-Key': os.environ['MUCANDA_API_KEY']})
        r.raise_for_status()
        pagina = r.json()
        clientes += pagina['itens']
        cursor = pagina['proximoCursor'] if pagina['itens'] else None
        if not cursor:
            return clientes

#Boas práticas

  • Use páginas grandes (200) para sincronizações e pequenas para ecrãs.
  • Respeite o limite de pedidos: numa importação grande, espere Retry-After quando receber 429.
  • Não guarde cursores durante muito tempo: servem para a listagem em curso, não como marcadores permanentes.
  • Para «o que mudou desde ontem», filtre por período nos documentos (dataInicio e dataFim) ou use alteradoDesde nos clientes, fornecedores e artigos (ver Sincronização incremental), em vez de repetir a listagem inteira.