REST in 2026: Best Practice, Versioning a Richardson Maturity Model
Většina rozhraní API, která se nazývají "RESTful", nejsou. Používají podobně jako HTTP transport, JSON jako formát a tam se zastavte. The Richardsonův model zralosti, představil Leonard Richardson v roce 2008 a popularizoval Martin Fowler, poskytuje a škálovat ve čtyřech úrovních, které odlišují generické HTTP API (úroveň 0) od skutečného API RESTful (úroveň 3 s HATEOAS).
Ale architektonický perfekcionismus není účelem této příručky. Cílem je naučit vás vytvářet REST API, která jsou správné, udržovatelné a dobře zdokumentované: používat vhodnou sémantiku HTTP, implementovat udržitelné verzování v průběhu času, spravovat cache efektivně s ETag a dokumentujte smlouvu s OpenAPI 3.1. Toto jsou skutečné rozdíly mezi profesionálním API a tím, které způsobuje problémy spotřebitelům.
Co se naučíte
- 4 úrovně Richardsonova modelu zralosti s konkrétními příklady
- Správná sémantika HTTP: metody, stavové kódy, hlavičky
- Idempotence a bezpečné metody: teoretické základy s praktickými aplikacemi
- Strategie verzování: URI, záhlaví a verzování prostřednictvím aditivních změn
- Etag a podmíněné požadavky na efektivní ukládání do mezipaměti
- OpenAPI 3.1: struktura dokumentu a osvědčené postupy
Richardsonův model dospělosti: 4 úrovně
Richardsonův model zralosti měří „RESTfulness“ API na stupnici 0 až 3. Pochopení těchto úrovní pomáhá identifikovat architektonické mezery do stávajících rozhraní API a vytvářet nová na správné úrovni.
Úroveň 0: HTTP jako transport (tunelování)
// Livello 0: tutto su un unico endpoint, azione nel body
POST /api
Content-Type: application/json
{
"action": "getUser",
"id": 123
}
POST /api
{
"action": "createUser",
"name": "Federico",
"email": "federico@example.com"
}
// HTTP e solo un canale: la semantica e tutta nell'applicazione
// Nessun caching possibile, nessuna semantica uniforme
Úroveň 1: Zdroje (smysluplné URI)
// Livello 1: URL per risorse, ma ancora solo POST
POST /users/123 // Non ha senso: POST per leggere?
POST /users/create
POST /users/delete/123
POST /users/get/all
// Migliore, ma i verbi HTTP non sono usati semanticamente
Úroveň 2: Slovesa HTTP (standardní úroveň)
// Livello 2: URL meaningful + verbi HTTP corretti + status codes
GET /users -> 200 OK con lista
GET /users/123 -> 200 OK con utente, 404 Not Found
POST /users -> 201 Created con Location header
PUT /users/123 -> 200 OK aggiornato, 404 Not Found
PATCH /users/123 -> 200 OK parzialmente aggiornato
DELETE /users/123 -> 204 No Content, 404 Not Found
// Questo e il livello che la maggior parte delle API raggiunge
// ed e generalmente sufficiente per la produzione
Úroveň 3: HATEOAS (Hypermedia jako motor stavu aplikace)
// Livello 3: ogni risposta contiene link alle azioni disponibili
GET /users/123
-> 200 OK
{
"id": 123,
"name": "Federico",
"email": "federico@example.com",
"status": "active",
"_links": {
"self": { "href": "/users/123" },
"orders": { "href": "/users/123/orders" },
"deactivate": { "href": "/users/123/deactivate", "method": "POST" },
"update": { "href": "/users/123", "method": "PUT" }
}
}
// Il client non deve "sapere" a priori gli URL: li scopre dalle risposte
// Permette di cambiare URL senza rompere i client (in teoria)
HATEOAS: Stojí to za to?
HATEOAS je teoreticky elegantní, ale v praxi se používá jen zřídka. Důvody:
- Výrazně zvyšuje velikost odezvy
- Klienti však často „pevně kódují“ adresy URL pro výkon
- Vyžaduje specifické nástroje pro navigaci v odkazech
- Většina týmů místo toho používá OpenAPI jako smlouvu
Úroveň 2 + OpenAPI 3.1 a pragmatická sladká tečka pro většinu API v roce 2026. HATEOAS má smysl hlavně ve veřejných API, kde je stabilita URL dlouhodobá termín a kritika.
Správná sémantika HTTP
Používání sloves HTTP se správnou sémantikou není jen estetický problém: má dopad ukládání do mezipaměti, idempotence a schopnost klientů bezpečně stahovat požadavky.
// Proprietà dei metodi HTTP
Metodo | Safe | Idempotente | Body richiesta | Uso corretto
--------|------|-------------|----------------|----------------------------------
GET | SI | SI | No | Lettura, query, ricerca
HEAD | SI | SI | No | Verifica esistenza, metadata
OPTIONS | SI | SI | No | CORS preflight, capabilities
POST | NO | NO | SI | Creazione, azioni non-idempotenti
PUT | NO | SI | SI | Sostituzione completa di risorsa
PATCH | NO | NO* | SI | Modifica parziale
DELETE | NO | SI | Opzionale | Eliminazione
// *PATCH puo essere reso idempotente con patch semantics JSON Patch (RFC 6902)
Trezor to znamená, že požadavek nemá žádné vedlejší účinky na straně serveru (server nemění stav). Klient může "stisknout F5" na GET bez následků.
Idempotentní znamená, že více stejných požadavků produkuje totéž výsledek jedné žádosti. Rozhodující pro opakování: pokud dojde k výpadku sítě během DELETE, klient to může zkusit znovu, aniž by se musel obávat smazání více než jednou.
Stavové kódy: Použijte ty správné
Zneužívání 200 OK na všechno (včetně chyb v těle) a jeden z antivzorů
běžnější. Použití správných kódů umožňuje klientům, proxy a monitorovacím nástrojům
správně interpretovat odpovědi:
// Status codes piu importanti con esempi di uso corretto
// 2xx: Success
200 OK - GET, PUT, PATCH con risorsa nel body
201 Created - POST che crea una risorsa (+ Location header)
202 Accepted - Operazione asincrona accettata (non ancora completata)
204 No Content - DELETE, PUT/PATCH senza body di risposta
// 3xx: Redirection
301 Moved Permanently - Redirect permanente (aggiornare i bookmark)
302 Found - Redirect temporaneo
304 Not Modified - ETag/If-None-Match: risorsa non cambiata, usa la cache
// 4xx: Client Error (il client ha sbagliato)
400 Bad Request - Input malformato, schema validation fallita
401 Unauthorized - Non autenticato (serve login)
403 Forbidden - Autenticato ma non autorizzato
404 Not Found - Risorsa non trovata
405 Method Not Allowed - Metodo HTTP non supportato su questo endpoint
409 Conflict - Conflitto di stato (es: email gia esistente)
410 Gone - Risorsa eliminata permanentemente (vs 404)
422 Unprocessable Entity - Sintassi ok ma semantica invalida
429 Too Many Requests - Rate limit raggiunto (+ Retry-After header)
// 5xx: Server Error (colpa del server)
500 Internal Server Error - Errore generico non gestito
502 Bad Gateway - Errore dal backend upstream
503 Service Unavailable - Server temporaneamente non disponibile
504 Gateway Timeout - Timeout dal backend upstream
PUT vs PATCH: Důležitý rozdíl
Záměna mezi PUT a PATCH je běžná, ale má konkrétní důsledky:
// PUT: sostituzione COMPLETA della risorsa (idempotente)
// Se ometti un campo, viene azzerato!
PUT /users/123
{
"name": "Federico Calo",
"email": "federico@example.com"
// Se il campo "phone" non e incluso, viene rimosso!
}
// PATCH: modifica PARZIALE (solo i campi specificati)
PATCH /users/123
{
"name": "Federico Calo"
// Solo name viene aggiornato, email e phone rimangono invariati
}
// PATCH con JSON Patch (RFC 6902): piu preciso e idempotente
PATCH /users/123
Content-Type: application/json-patch+json
[
{ "op": "replace", "path": "/name", "value": "Federico Calo" },
{ "op": "add", "path": "/phone", "value": "+39 333 1234567" },
{ "op": "remove", "path": "/tempNote" }
]
Strategie verzování
Správa verzí je jedním z nejdůležitějších rozhodnutí při navrhování veřejného API. Jednou že klienti závisejí na API, změna smlouvy přeruší jejich aplikace. Le Hlavní strategie mají různé kompromisy:
1. Verze URI (nejběžnější)
GET /api/v1/users // Versione 1
GET /api/v2/users // Versione 2 con campi aggiuntivi
// Vantaggi:
// - Visibile e ovvio
// - Cacheable a livello HTTP (l'URL e diverso)
// - Facile da esplorare con il browser
// - Semplice da loggare e monitorare
// Svantaggi:
// - "Sporco" semanticamente (la versione non e parte della risorsa)
// - Proliferazione di URL nel tempo
2. Verze záhlaví
GET /api/users
Accept: application/vnd.myapi.v2+json
// oppure
API-Version: 2
// Vantaggi:
// - URL "puliti"
// - Piu vicino alla semantica HTTP originale
// Svantaggi:
// - Non cacheable con HTTP standard (Cache-Vary header necessario)
// - Invisibile dalla URL (difficile da debuggare)
// - Meno intuitivo per i nuovi consumatori dell'API
3. Verze pomocí aditivních změn (nejlepší)
// Strategia: non cambiare mai, solo aggiungere (non rompere mai i client)
// V1 risposta:
GET /api/users/123
{
"id": 123,
"name": "Federico",
"email": "federico@example.com"
}
// Aggiungi campi senza versione (i client vecchi ignorano i nuovi campi):
GET /api/users/123
{
"id": 123,
"name": "Federico",
"email": "federico@example.com",
"createdAt": "2025-01-15T10:30:00Z", // AGGIUNTO: non rompe i client vecchi
"avatarUrl": null // AGGIUNTO: nullable per retrocompat
}
// Quando DEVI rompere (rare):
// - Rimuovere un campo -> versione nuova
// - Cambiare tipo di un campo -> versione nuova
// - Cambiare semantica di un campo -> versione nuova
Etag a podmíněné požadavky
L'Etag (Entity Tag) a mechanismus HTTP pro správu mezipaměti a optimistická konkurence. Každý zdroj má hash nebo časové razítko, které identifikuje jeho verzi aktuální:
// Server: risposta con ETag
GET /users/123
->
200 OK
ETag: "abc123def456"
Cache-Control: max-age=300
{
"id": 123,
"name": "Federico",
"version": 3
}
// Client: richiesta condizionale con If-None-Match
GET /users/123
If-None-Match: "abc123def456"
->
304 Not Modified // Risorsa non cambiata, usa la cache!
// Nessun body = traffico ridotto
// Se la risorsa e cambiata:
GET /users/123
If-None-Match: "abc123def456"
->
200 OK
ETag: "xyz789new123" // Nuovo ETag
{ /* dati aggiornati */ }
// ETag per concorrenza ottimistica (prevenire aggiornamenti in conflitto):
PUT /users/123
If-Match: "abc123def456" // "Aggiorna SOLO se la versione e ancora questa"
{...}
->
200 OK // Aggiornamento riuscito, nessun conflitto
// oppure
412 Precondition Failed // Qualcun altro ha modificato la risorsa!
// Il client deve rileggere prima di riaggiornare
Dokumentace pomocí OpenAPI 3.1
OpenAPI 3.1 je průmyslový standard pro dokumentaci REST API. Pěkný dokument OpenAPI písemné slouží jako formální smlouva, umožňuje generování klientských SDK a pravomocí Interaktivní dokumentace s Swagger UI nebo Redoc:
// openapi.yaml - Struttura base di un documento OpenAPI 3.1
openapi: 3.1.0
info:
title: User Management API
version: 1.2.0
description: |
API per la gestione degli utenti dell'applicazione.
## Autenticazione
Usa Bearer token JWT nell'header Authorization.
contact:
name: API Support
email: api@example.com
license:
name: MIT
servers:
- url: https://api.example.com/v1
description: Production
- url: https://staging-api.example.com/v1
description: Staging
paths:
/users:
get:
operationId: listUsers
summary: Lista utenti
tags: [Users]
parameters:
- name: page
in: query
schema: { type: integer, minimum: 1, default: 1 }
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
- name: search
in: query
schema: { type: string }
responses:
'200':
description: Lista utenti paginata
content:
application/json:
schema:
$ref: '#/components/schemas/UserListResponse'
'401':
$ref: '#/components/responses/Unauthorized'
post:
operationId: createUser
summary: Crea utente
tags: [Users]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
responses:
'201':
description: Utente creato
headers:
Location:
schema: { type: string }
description: URL del nuovo utente
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
$ref: '#/components/responses/BadRequest'
'409':
description: Email gia esistente
components:
schemas:
User:
type: object
required: [id, name, email, createdAt]
properties:
id: { type: integer, format: int64, readOnly: true }
name: { type: string, minLength: 1, maxLength: 100 }
email: { type: string, format: email }
createdAt: { type: string, format: date-time, readOnly: true }
CreateUserRequest:
type: object
required: [name, email, password]
properties:
name: { type: string, minLength: 1, maxLength: 100 }
email: { type: string, format: email }
password: { type: string, minLength: 8, writeOnly: true }
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
Vzor chybových odpovědí
Konzistentní struktura chybových odpovědí dramaticky zlepšuje vývojáře Spotřebitelská zkušenost API. Standard RFC 9457 (podrobnosti o problému) a stal se preferovanou volbou v roce 2026:
// RFC 9457 Problem Details for HTTP APIs
// Content-Type: application/problem+json
// 400 Bad Request
{
"type": "https://example.com/errors/validation-error",
"title": "Validation Error",
"status": 400,
"detail": "The request body contains invalid data",
"instance": "/api/users",
"errors": [
{
"field": "email",
"message": "Invalid email format",
"value": "not-an-email"
},
{
"field": "password",
"message": "Password must be at least 8 characters",
"value": null
}
]
}
// 409 Conflict
{
"type": "https://example.com/errors/duplicate-email",
"title": "Duplicate Email",
"status": 409,
"detail": "An account with this email already exists",
"instance": "/api/users",
"email": "federico@example.com"
}
// 429 Too Many Requests
{
"type": "https://example.com/errors/rate-limited",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "Too many requests. Retry after 60 seconds.",
"retryAfter": 60
}
Závěry a další kroky
Profesionální REST API v roce 2026 funguje na úrovni 2 Richardsonova modelu zralosti (zdroje + správná HTTP slovesa + příslušné stavové kódy), použijte ETag pro ukládání do mezipaměti a optimistickou souběžnost, přijímá udržitelné verzování založené na aditivních změnách a dokumentuje formální smlouvu s OpenAPI 3.1. Ve většině kontextů není nutné dosáhnout úrovně HATEOAS 3.
Další článek zkoumá GraphQL do hloubky: jak systém funguje překladačů, protože problém N+1 je nejběžnějším architektonickým rizikem, a jako DataLoader řeší dávkování databázových dotazů.
Řada: Design API – porovnání REST, GraphQL, gRPC a tRPC
- Článek 1: Krajina API v roce 2026 – rozhodovací matice
- Článek 2 (tento): REST in 2026 — Best Practice, Versioning a Richardson Maturity Model
- Článek 3: GraphQL – Dotazovací jazyk, Resolver a problém N+1
- Článek 4: GraphQL Federation — Supergraph, Subgraph a Apollo Router
- Článek 5: gRPC – Protobuf, Performance a Service-to-Service Communication
- Článek 6: tRPC – typová bezpečnost end-to-end bez generování kódu
- Článek 7: Webhooky – vzory, zabezpečení a logika opakování
- Článek 8: Verze rozhraní API – Zásady URI, záhlaví a ukončení podpory
- Článek 9: Omezení a omezování rychlosti – Algoritmy a implementace
- Článek 10: Hybrid API Architecture – REST + tRPC + gRPC v roce 2026







