Návrh REST API: URL, HTTP metody, status kódy a verzování
Praktická pravidla pro návrh REST API: pojmenování endpointů, správné HTTP status kódy, formát chyb, stránkování, idempotence a verzování.
Dobré API se pozná tak, že ho vývojář pochopí z pár příkladů a nemusí luštit dokumentaci. Tento článek shrnuje osvědčené konvence pro REST API nad HTTP – co dát do URL, jaký status kód vracet a jak API verzovat, aby změny nerozbily klienty.
URL jsou podstatná jména
Endpoint popisuje zdroj, akci určuje HTTP metoda:
| Metoda a URL | Význam |
|---|---|
GET /orders |
seznam objednávek |
POST /orders |
vytvoření objednávky |
GET /orders/42 |
detail |
PATCH /orders/42 |
částečná úprava |
PUT /orders/42 |
nahrazení celého zdroje |
DELETE /orders/42 |
smazání |
GET /customers/7/orders |
objednávky zákazníka |
Vyhněte se slovesům v URL (/getOrders, /createOrder). Výjimkou jsou akce, které se do CRUD nevejdou – pak je čitelné POST /orders/42/cancel.
Další konvence: množné číslo, malá písmena, slova oddělená pomlčkou (/payment-methods), vnoření maximálně o jednu úroveň.
Status kódy, které opravdu potřebujete
Úspěch (2xx)
- 200 OK – běžná úspěšná odpověď s tělem.
- 201 Created – po
POST, který vytvořil zdroj. Přidejte hlavičkuLocation: /orders/43. - 202 Accepted – požadavek přijat, zpracuje se asynchronně (fronta).
- 204 No Content – úspěch bez těla, typicky
DELETE.
Chyby klienta (4xx)
- 400 Bad Request – nevalidní JSON nebo chybná struktura požadavku.
- 401 Unauthorized – chybí nebo je neplatné ověření (název je historicky zavádějící, jde o autentizaci).
- 403 Forbidden – uživatel je známý, ale nemá oprávnění.
- 404 Not Found – zdroj neexistuje. Lze použít i místo 403, pokud nechcete prozradit, že zdroj existuje.
- 405 Method Not Allowed – metoda není pro endpoint podporována.
- 409 Conflict – konflikt stavu: duplicitní e-mail, souběžná úprava.
- 422 Unprocessable Content – syntakticky správný požadavek s neplatnými hodnotami (validace polí).
- 429 Too Many Requests – překročený rate limit, ideálně s hlavičkou
Retry-After.
Chyby serveru (5xx)
- 500 Internal Server Error – neočekávaná chyba. Nikdy nevracejte stack trace klientovi.
- 502 / 503 / 504 – problém upstreamu, údržba, timeout.
Nejhorší praxe: vracet 200 OK s tělem {"success": false}. Rozbíjí to cache, monitoring i HTTP klienty, kteří chyby rozpoznávají podle kódu.
Jednotný formát chyb
Existuje standard RFC 9457 (Problem Details, nahradil RFC 7807) s typem application/problem+json:
{
"type": "https://api.example.cz/errors/validation",
"title": "Neplatná data",
"status": 422,
"detail": "Některá pole nejsou vyplněna správně.",
"errors": [
{ "field": "email", "message": "Neplatný formát e-mailu" }
]
}
Ať už standard použijete nebo ne, hlavní je, aby všechny endpointy vracely chyby ve stejném tvaru a se strojově čitelným kódem, na který může klient reagovat.
Stránkování, filtrování, řazení
GET /orders?status=paid&sort=-created_at&limit=20&cursor=eyJpZCI6MTAwfQ
- Offset (
?page=3&per_page=20) je jednoduchý, ale u velkých tabulek pomalý a při vkládání nových záznamů se položky posouvají. - Cursor (
?cursor=...) odkazuje na poslední vrácený záznam, je stabilní a rychlý. Hodí se pro feedy a velké seznamy.
Odpověď:
{
"data": [ { "id": 99, "status": "paid" } ],
"next_cursor": "eyJpZCI6OTl9"
}
Vždy nastavte maximální limit, jinak si někdo stáhne celou tabulku jedním požadavkem.
Idempotence
GET, PUT a DELETE mají být idempotentní – opakované volání má stejný efekt jako jedno. POST není: když klientovi vypadne spojení a pošle požadavek znovu, vzniknou dvě objednávky.
Řešením je hlavička Idempotency-Key, kterou používá například Stripe:
POST /payments
Idempotency-Key: 3f1c9a2e-7b4d-4c1e-9a55-2d8f0e6b1c77
Server si klíč uloží s výsledkem a při opakování vrátí původní odpověď místo nového zpracování.
Verzování
Nejčastější a nejsrozumitelnější je verze v URL:
https://api.example.cz/v1/orders
Alternativy jsou hlavička (Accept: application/vnd.example.v2+json) nebo datum verze v hlavičce. Ty jsou „čistší“, ale hůř se ladí v prohlížeči a curlu.
Co je zpětně kompatibilní (nepotřebuje novou verzi):
- přidání nového endpointu,
- přidání nepovinného parametru,
- přidání pole do odpovědi.
Co kompatibilitu rozbíjí:
- odebrání nebo přejmenování pole,
- změna typu (
"id": 42→"id": "42"), - nové povinné pole v požadavku,
- změna významu status kódu.
Klienti by měli neznámá pole ignorovat. Starou verzi ohlaste dopředu a můžete použít hlavičky Deprecation a Sunset (RFC 8594).
Drobnosti, které dělají rozdíl
- Časy ve formátu ISO 8601 s časovou zónou:
2026-10-12T14:30:00Z. - Konzistentní styl klíčů v JSONu – buď
snake_case, nebocamelCase, ne obojí. - Částky v nejmenší jednotce (haléře) jako celé číslo, plus kód měny.
- Pouze HTTPS.
- Popis API ve formátu OpenAPI 3 – z něj vygenerujete dokumentaci i klienty.
Rychlá kontrola
curl -i -X POST https://api.example.cz/v1/orders \
-H "Content-Type: application/json" \
-d '{"customer_id": 7}'
Přepínač -i ukáže status kód i hlavičky. Pokud vytvoření vrátí 201 s Location, chybná data 422 se srozumitelnou chybou a neexistující ID 404, jste na dobré cestě.