# Paginazione

> Come percorrere qualsiasi collezione con un cursore opaco, e come tenerne aggiornata una copia.

Source: https://developers.backresto.com/it/docs/pagination

Ogni elenco di questa API si legge allo stesso modo: si percorre una
[collezione](https://developers.backresto.com/it/docs/collections) pagina per pagina, consegne comprese.

```http
GET /v1/restaurants/{restaurantId}/collections/{collection}/records
  ?limit=100
  &cursor=eyJpZCI6…
```

| Parametro | Obbligatorio | Regole |
| --- | --- | --- |
| `limit` | no | Da 1 a 100. Il valore predefinito è 50. |
| `cursor` | no | Il `nextCursor` della pagina precedente, invariato. |

La risposta è `{ "data": [...], "nextCursor": string | null }`.

## Nessun intervallo di tempo

Non ci sono né `from` né `to`. Un record cambia sul posto (una correzione, un
tombstone), quindi si percorre la collezione e si riconcilia anziché chiederne
una finestra. Per leggere una settimana di consegne, percorra `deliveries` e
tenga i record il cui `data.timestamp` cade all'interno della settimana.

## Ordinamento

Dalla modifica più vecchia: in ordine crescente per `sequence`, la posizione
dell'ultima modifica di ciascun record nel flusso. Confronti due valori di
`sequence`; non ci faccia aritmetica sopra.

## Percorrere le pagine

`nextCursor` è `null` sull'ultima pagina e una stringa altrimenti. Lo rimandi
indietro intatto: è una posizione opaca, non un documento da analizzare, e la
sua struttura interna cambierà senza preavviso.

```js
async function* records({ apiKey, restaurantId, collection }) {
  const base = `https://api.backresto.com/v1/restaurants/${restaurantId}/collections/${collection}/records`;
  let cursor = null;

  do {
    const url = new URL(base);
    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);
}
```

**Un percorso è uno snapshot coerente.** La prima pagina fissa la posizione nel
flusso, e ogni pagina successiva viene servita a partire da quella stessa
posizione. I record scritti mentre sta paginando non le spostano le pagine sotto
i piedi. Li vedrà al percorso successivo.

Il cursore è legato al ristorante, alla collezione **e al limit**. Se cambia la
dimensione della pagina a metà percorso risponde `400`: scelga un limit e lo
mantenga per tutto il percorso.

## Tenere aggiornata una copia

Oggi non esiste un parametro `since`. Un aggiornamento è un altro percorso, e lo
riconcilia con quello che già possiede:

- **Usi `id` come chiave** all'interno di una collezione, e sovrascriva quando
  il `sequence` che riceve è più alto di quello che ha memorizzato.
- **Rispetti i tombstone.** `deleted: true` è l'istruzione di cancellazione;
  applicarla è l'unico modo perché la sua copia smetta di divergere.
- **Metta in conto gli arrivi tardivi.** Un dispositivo che era offline durante
  il servizio carica i dati quando si riconnette, quindi un record può comparire
  dopo un percorso che avrebbe coperto il suo `data.timestamp`. Basi i report su
  `capturedAt`, la sincronizzazione su `receivedAt`.

Una pagina vuota non è la prova che non sia successo nulla. Veda
[la nota sulla completezza](https://developers.backresto.com/it/docs/support).
