# Paginierung

> Wie Sie jede Collection mit einem undurchsichtigen Cursor durchlaufen und wie Sie eine Kopie davon aktuell halten.

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

Jede Liste in dieser API wird auf dieselbe Weise gelesen: Sie durchlaufen eine
[Collection](https://developers.backresto.com/de/docs/collections) Seite für Seite, Lieferungen eingeschlossen.

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

| Parameter | Pflicht | Regeln |
| --- | --- | --- |
| `limit` | nein | 1 bis 100. Standard ist 50. |
| `cursor` | nein | Der `nextCursor` der vorherigen Seite, wortgleich. |

Die Antwort ist `{ "data": [...], "nextCursor": string | null }`.

## Kein Zeitraum

Es gibt kein `from` und kein `to`. Ein Datensatz ändert sich an Ort und Stelle
(eine Korrektur, ein Tombstone), Sie durchlaufen also die Collection und gleichen
ab, statt einen Ausschnitt von ihr anzufragen. Um eine Woche an Lieferungen zu
lesen, durchlaufen Sie `deliveries` und behalten die Datensätze, deren
`data.timestamp` in diese Woche fällt.

## Sortierung

Älteste Änderung zuerst: aufsteigend nach `sequence`, der Position der letzten
Änderung jedes Datensatzes im Strom. Vergleichen Sie zwei `sequence`-Werte;
rechnen Sie nicht mit einem.

## Die Seiten durchlaufen

`nextCursor` ist auf der letzten Seite `null` und sonst ein String. Geben
Sie ihn unverändert zurück: Er ist eine undurchsichtige Position und kein
Dokument zum Parsen, und sein Innenleben ändert sich ohne Ankündigung.

```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);
}
```

**Ein Durchlauf ist ein konsistenter Snapshot.** Die erste Seite fixiert die
Position im Strom, und jede spätere Seite wird zu genau dieser Position
beantwortet. Datensätze, die geschrieben werden, während Sie blättern,
verschieben die Seiten unter Ihnen nicht. Sie sehen sie beim nächsten Durchlauf.

Der Cursor ist an das Restaurant, die Collection **und das Limit** gebunden.
Ändern Sie die Seitengröße mitten im Durchlauf, antwortet er `400`: Wählen Sie
ein Limit und behalten Sie es für den ganzen Durchlauf.

## Eine Kopie aktuell halten

Es gibt heute keinen `since`-Parameter. Eine Auffrischung ist ein weiterer
Durchlauf, und Sie gleichen ihn mit dem ab, was Sie schon halten:

- **Nutzen Sie `id` als Schlüssel** innerhalb einer Collection und überschreiben
  Sie, wenn die `sequence`, die Sie bekommen, höher ist als die gespeicherte.
- **Werten Sie Tombstones aus.** `deleted: true` ist die Anweisung zu löschen;
  sie anzuwenden ist der einzige Weg, auf dem Ihre Kopie aufhört
  auseinanderzulaufen.
- **Rechnen Sie mit Nachzüglern.** Ein Gerät, das während des Betriebs offline
  war, lädt hoch, sobald es sich wieder verbindet; ein Datensatz kann also nach
  einem Durchlauf erscheinen, der sein `data.timestamp` bereits abgedeckt hätte.
  Berichten Sie nach `capturedAt`, synchronisieren Sie nach `receivedAt`.

Eine leere Seite ist kein Beweis, dass nichts passiert ist (siehe
[die Anmerkung zur Vollständigkeit](https://developers.backresto.com/de/docs/support)).
