Praktický návod

Jak implementovat stránkování API

Vracej omezené a předvídatelné části kolekce. Klient nesmí stáhnout milion řádků jedním requestem.

25 minut · API

Nejdřív stručně

Offset, nebo cursor?

Pagination dělí kolekci v API na menší stránky. Parametr limit určuje velikost stránky a offset počet přeskočených záznamů. Je to jednoduché, ale vysoký offset bývá pomalý a při změnách kolekce může položky vynechat nebo zopakovat.

Cursor označuje poslední viděnou pozici ve stabilním řazení. Klient ho pošle v query stringu a server pokračuje za ní. Pro velký nebo průběžně měněný seznam je cursor obvykle bezpečnější.

Připrav si

Co musíš rozhodnout předem

Stránkování je součást kontraktu endpointu. Nejdřív definuj pořadí a teprve potom parametry.

  • Kolekční endpoint, například GET /api/products.
  • Stabilní a jednoznačné řazení. Samotné created_at nestačí; doplň ho unikátním id.
  • Výchozí a maximální limit, například 25 a 100. Hodnotu z requestu vždy validuj a omez.
  • Rozhodnutí, zda klient potřebuje přesný celkový počet položek. COUNT nad velkou tabulkou může být drahý.

Kroky 1 až 3

Navrhni stabilní stránkovací kontrakt

Začni jednoduchým tvarem odpovědi a u databázového dotazu zachovej stejné řazení na každé stránce.

1. Definuj parametry a odpověď

  1. Přijmi limit, nastav výchozí hodnotu a omez ji na rozumné maximum. Neplatné číslo vrať jako chybu 400, nebo zdokumentuj jeho normalizaci.
  2. Nedovol klientovi libovolný sloupec řazení. Přijmi jen předem povolené hodnoty a směr ASC nebo DESC.
  3. JSON odpověď drž konzistentní: items obsahuje data a page objekt další cursor, informaci hasMore nebo použitý limit.
  4. Celkový počet vracej jen tehdy, když ho klient opravdu potřebuje a umíš ho spočítat levně. Cursorové stránkování ho ke své funkci nepotřebuje.
GET /api/products?limit=25
HTTP standard k práci s URI

2. Pro malé stabilní seznamy použij offset

  1. Pro administraci nebo krátký katalog může být limit a offset nejčitelnější volba. První stránka má offset 0, druhá offset rovný limitu.
  2. V SQL vždy přidej ORDER BY. Bez něj databáze negarantuje stejné pořadí mezi dvěma requesty.
  3. Řadíš-li podle neunikátní hodnoty, doplň unikátní tie-breaker: ORDER BY created_at DESC, id DESC.
  4. Počítej s tím, že vložený nebo smazaný řádek před aktuálním offsetem může posunout následující stránku.
SELECT id, name, created_at
FROM product
ORDER BY created_at DESC, id DESC
LIMIT :limit OFFSET :offset;
Oficiální PostgreSQL dokumentace k LIMIT a OFFSET

3. Pro velké nebo živé seznamy použij cursor

  1. Cursor vytvoř z poslední položky stránky, například z dvojice created_at a id. Klient ho má pouze vrátit; nemusí rozumět jeho obsahu.
  2. Hodnoty zakóduj do neprůhledného řetězce, po přijetí je bezpečně dekóduj a validuj. Pokud cursor chrání oprávnění nebo filtry, také ho podepiš.
  3. Dotaz pokračuje striktně za poslední dvojicí. Směr porovnání musí odpovídat směru ORDER BY.
  4. Načti limit + 1 řádků. Přebytečný řádek řekne, že existuje další stránka; klientovi ho neposílej.
SELECT id, name, created_at
FROM product
WHERE (created_at, id) < (:createdAt, :id)
ORDER BY created_at DESC, id DESC
LIMIT :limitPlusOne;
Oficiální PostgreSQL dokumentace k porovnání řádků

Krok 4

Otestuj hranice mezi stránkami

Nejdůležitější chyby vznikají při přechodu na další stránku a při souběžné změně dat.

  1. Projdi celou kolekci

    Začni bez cursoru a pokračuj pomocí nextCursor, dokud hasMore není false. Žádné ID se nesmí opakovat a počet položek na stránce nesmí překročit limit.

    curl -s 'http://localhost:8000/api/products?limit=2'
  2. Vlož záznam mezi dvěma requesty

    Po načtení první stránky přidej nový produkt a pokračuj cursorem. Již vrácené položky se nemají objevit znovu.

  3. Ověř neplatné vstupy

    Vyzkoušej limit 0, záporný offset, limit nad maximem a poškozený cursor. Endpoint má vrátit předvídatelnou chybu, ne databázovou výjimku.

    curl -i 'http://localhost:8000/api/products?limit=25&cursor=broken'

Když to zlobí

Nejčastější chyby

Položka se objeví na dvou stránkách

Ověř jednoznačné řazení a zahrň všechny jeho hodnoty do cursoru. created_at bez unikátního id není stabilní hranice.

Dotaz s vysokým offsetem zpomaluje

Databáze musí přeskočené řádky stále najít. Přejdi na cursorové stránkování a přidej index odpovídající filtrům a ORDER BY.

Další stránka je prázdná, i když hasMore bylo true

hasMore odvozuj z načtení limit + 1, ne z toho, že stránka má právě limit položek. Data se také mohla mezi requesty změnit; prázdnou stránku musí klient bezpečně zvládnout.

Cursor lze použít s jiným filtrem

Zahrň do podepsaného cursoru otisk relevantních filtrů a řazení, nebo cursor při jejich změně odmítni. Jinak hranice nepatří ke stejnému seznamu.

Hotovo

API vrací předvídatelné stránky.

API teď chrání databázi limitem a klientovi dává stabilní cestu kolekcí. Offset nech pro malé seznamy; cursor použij tam, kde data rostou nebo se za běhu mění.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.