Paginação e intervalos de tempo
Como percorrer as entregas e os registos de uma coleção com um cursor opaco, e porque é que uma recebe um intervalo de tempo e a outra não.
Dois endpoints paginam, e fazem-no de maneira diferente de propósito:
| Lista | Intervalo | Ordenação | O cursor está ligado a |
|---|---|---|---|
| Entregas | from e to, obrigatórios, no máximo 366 dias | Do mais recente para o mais antigo | O intervalo que pediu |
| Registos de uma coleção | nenhum — percorre a coleção inteira | Da alteração mais antiga para a mais recente | Restaurante, coleção e limit |
Ambas respondem { "data": [...], "nextCursor": string | null }, ambas limitam
o limit a 100 com 50 por omissão, e ambas querem o cursor devolvido intacto. O
resto desta página é sobre a lista de entregas; a
página das coleções trata da outra.
As entregas são imutáveis e interessam por data, por isso recebem um intervalo. Os registos de uma coleção mudam no sítio, por isso um intervalo sobre eles seria uma mentira — percorre-se a coleção e reconcilia-se.
A lista de entregas
Recebe um intervalo de tempo explícito e obrigatório e devolve uma página mais um cursor opaco.
GET /v1/restaurants/{restaurantId}/deliveries
?from=1787846400000
&to=1788451200000
&limit=50
&cursor=eyJpZCI6…
| Parâmetro | Obrigatório | Regras |
|---|---|---|
from | sim | Milissegundos desde a época Unix, como uma cadeia de dígitos. Inclusivo. |
to | sim | Milissegundos desde a época Unix, como uma cadeia de dígitos. Inclusivo. |
limit | não | De 1 a 100. Por omissão, 50. |
cursor | não | O nextCursor da página anterior, tal e qual. |
to tem de ser maior ou igual a from, e o intervalo tem de ser de, no
máximo, 366 dias. Qualquer outra coisa responde 400. O intervalo é
obrigatório em vez de assumido por omissão porque um intervalo assumido é a
forma como uma integração começa, sem ninguém dar por isso, a reler uma década
de registos todas as noites.
Ordenação
Do mais recente para o mais antigo: por occurredAt descendente, depois por
id descendente para desempatar. Duas entregas registadas no mesmo milissegundo
têm, por isso, uma ordem estável e repetível, que é o que torna o cursor sólido.
Percorrer as páginas
nextCursor é null na última página e uma cadeia de caracteres nas restantes.
Devolva-o intacto — é uma posição codificada em base64url, não um documento
para analisar, e o seu conteúdo vai mudar sem aviso.
async function* deliveries({ apiKey, restaurantId, from, to }) {
const base = `https://api.backresto.com/v1/restaurants/${restaurantId}/deliveries`;
let cursor = null;
do {
const url = new URL(base);
url.searchParams.set('from', from);
url.searchParams.set('to', to);
url.searchParams.set('limit', '100');
if (cursor !== null) {
url.searchParams.set('cursor', cursor);
}
const response = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` }
});
if (!response.ok) {
throw new Error(`BackResto ${response.status}`);
}
const page = await response.json();
yield* page.data;
cursor = page.nextCursor;
} while (cursor !== null);
}
Mantenha from e to idênticos em todas as páginas de um percurso. O cursor
codifica uma posição dentro do intervalo que pediu; mudar o intervalo a meio do
percurso não é um pedido suportado e não lhe vai dar o que espera.
Consultar de forma incremental
As entregas são imutáveis assim que registadas, por isso uma consulta
incremental é simples: guarde o occurredAt do registo mais recente que tem
armazenado e use-o como o from seguinte.
Dois pormenores que vale a pena implementar:
- Sobreponha de propósito. Comece a janela seguinte um pouco antes do último
registo que viu — uma hora chega — e elimine duplicados pelo
id. Um dispositivo que esteve offline durante o serviço envia os dados quando volta a ligar-se, por isso uma entrega pode tornar-se visível depois de uma consulta que já cobria a sua data e hora. - Nunca alargue para além de 366 dias. Se o seu processo não corre há muito tempo, percorra o intervalo em janelas de um ano em vez de o pedir todo de uma vez.
Uma página vazia não é prova de que nada aconteceu — veja a nota sobre a completude dos dados.