# Pagination

> Comment parcourir n'importe quelle collection avec un curseur opaque, et comment en maintenir une copie à jour.

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

Toutes les listes de cette API se lisent de la même façon : vous parcourez une
[collection](https://developers.backresto.com/fr/docs/collections) page par page, livraisons comprises.

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

| Paramètre | Obligatoire | Règles |
| --- | --- | --- |
| `limit` | non | De 1 à 100. 50 par défaut. |
| `cursor` | non | Le `nextCursor` de la page précédente, tel quel. |

La réponse est `{ "data": [...], "nextCursor": string | null }`.

## Pas de plage de temps

Il n'y a ni `from` ni `to`. Un enregistrement change sur place (une correction,
un tombstone), vous parcourez donc la collection et vous réconciliez plutôt que
de demander une fenêtre de celle-ci. Pour lire une semaine de livraisons,
parcourez `deliveries` et gardez les enregistrements dont le `data.timestamp`
tombe dans la semaine.

## Tri

Le changement le plus ancien d'abord : croissant sur `sequence`, la position du
dernier changement de chaque enregistrement dans le flux. Comparez deux valeurs
de `sequence` ; ne faites pas d'arithmétique sur une seule.

## Parcourir les pages

`nextCursor` vaut `null` sur la dernière page et une chaîne de caractères
sinon. Renvoyez-le tel quel : c'est une position opaque, pas un document à
analyser, et ses entrailles changeront sans préavis.

```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 parcours est un snapshot cohérent.** La première page fixe la position du
flux, et chaque page suivante est servie à partir de cette même position. Les
enregistrements écrits pendant que vous paginez ne décalent pas les pages sous
vos pieds : vous les verrez au parcours suivant.

Le curseur est lié au restaurant, à la collection **et à la limite**. Changez
la taille de page en cours de parcours et il répond `400` : choisissez une
limite, gardez-la pour tout le parcours.

## Maintenir une copie à jour

Il n'y a pas de paramètre `since` aujourd'hui. Une actualisation, c'est un
nouveau parcours, et vous réconciliez avec ce que vous détenez déjà :

- **Indexez sur `id`** au sein d'une collection, et écrasez quand le `sequence`
  que vous recevez est supérieur à celui que vous aviez stocké.
- **Respectez les tombstones.** `deleted: true` est l'instruction de
  suppression ; l'appliquer est la seule façon d'empêcher votre copie de
  diverger.
- **Attendez-vous à des arrivées tardives.** Un appareil resté hors ligne
  pendant le service téléverse quand il se reconnecte, un enregistrement peut
  donc apparaître après un parcours qui aurait couvert son `data.timestamp`.
  Faites vos rapports sur `capturedAt`, synchronisez sur `receivedAt`.

Une page vide n'est pas la preuve que rien ne s'est passé. Voyez
[la note sur l'exhaustivité](https://developers.backresto.com/fr/docs/support).
