Skip to content

How-to: Offset- und Cursor-Paginierung

FT-Referenz: FT325 (NENE2-FT/pagelog) — Duale Paginierungsstrategie (offset-basiert und cursor-basiert) mit next_offset/next_cursor, has_more, Kategorie-Filter, 15 Tests / 47 Assertions PASS.

Diese Anleitung zeigt, wie beide Paginierungsstrategien — offset-basiert und cursor-basiert — für dieselbe Ressource implementiert werden, sodass Clients die für ihren Anwendungsfall passende Strategie wählen können.

Schema

sql
CREATE TABLE articles (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    title      TEXT    NOT NULL,
    author     TEXT    NOT NULL,
    category   TEXT    NOT NULL DEFAULT 'general',
    created_at TEXT    NOT NULL
);

Endpunkte

MethodePfadBeschreibung
POST/articlesArtikel erstellen
GET/articles/offsetOffset-Paginierung
GET/articles/cursorCursor-Paginierung
GET/articles/by-categoryKategorie-Filter

Offset-Paginierung

GET /articles/offset?limit=10&offset=0
→ 200
{
  "items": [...],     // 10 Artikel
  "total": 25,
  "limit": 10,
  "offset": 0,
  "has_more": true,
  "next_offset": 10   // null auf letzter Seite
}

// Seite 2
GET /articles/offset?limit=10&offset=10
→ {"items": [...], "has_more": true, "next_offset": 20}

// Letzte Seite
GET /articles/offset?limit=10&offset=20
→ {"items": [...], "has_more": false, "next_offset": null}

// Jenseits des Endes
GET /articles/offset?limit=10&offset=100
→ {"items": [], "has_more": false}

next_offset = offset + limit wenn has_more, sonst null.

Cursor-Paginierung

GET /articles/cursor?limit=10
→ 200
{
  "items": [...],        // neueste zuerst
  "has_more": true,
  "next_cursor": 15      // id des letzten zurückgegebenen Artikels
}

// Nächste Seite mit Cursor
GET /articles/cursor?limit=10&after=15
→ {"items": [...], "has_more": true, "next_cursor": 5}

// Letzte Seite
GET /articles/cursor?limit=10&after=5
→ {"items": [...], "has_more": false, "next_cursor": null}

Cursor ist die id des zuletzt zurückgegebenen Artikels: WHERE id < $after ORDER BY id DESC LIMIT $limit + 1 (einen Extra-Eintrag vorausschauen, um has_more zu bestimmen).

Kategorie-Filter

GET /articles/by-category?category=tech&limit=5
→ {"items": [...], "total": N}

Offset vs. Cursor — Wann verwenden

KriteriumOffsetCursor
Zufälliger Seitensprung?offset=50❌ Muss traversieren
Gesamtanzahl benötigt✅ Immer enthalten❌ Teuer
Konsistente Ergebnisse bei Inserts❌ Neue Zeile verschiebt Seite✅ Stabil
Performance bei großen DatensätzenOFFSET N scannt N ZeilenWHERE id < X nutzt Index
Infinite Scroll / Feed

Was man NICHT tun sollte

Anti-MusterRisiko
next_offset auch auf letzter Seite zurückgebenClient macht eine zusätzliche leere Anfrage
OFFSET N auf Tabellen mit Millionen Zeilen verwendenDB scannt N Zeilen vor der Rückgabe; bei großen Daten Cursor verwenden
has_more aus Cursor-Antwort weglassenClient kann nicht wissen, ob die nächste Seite abgerufen werden soll
Timestamp als Cursor verwendenDoppelte Timestamps verursachen übersprungene oder wiederholte Zeilen; einzigartigen Integer-ID verwenden

Veröffentlicht unter der MIT-Lizenz.