REST în 2026: cele mai bune practici, versiunea și modelul de maturitate Richardson
Majoritatea API-urilor care se numesc „RESTful” nu sunt. Ei folosesc HTTP ca transport, JSON ca format și opriți-vă acolo. The Modelul de maturitate Richardson, introdus de Leonard Richardson în 2008 și popularizat de Martin Fowler, oferă a scala în patru niveluri care distinge un API HTTP generic (nivel 0) de un API cu adevărat RESTful (nivelul 3 cu HATEOAS).
Dar perfecționismul arhitectural nu este scopul acestui ghid. Scopul este să te învețe pentru a construi API-uri REST care sunt corect, întreținut și bine documentat: utilizați semantică HTTP adecvată, implementați versiunea durabilă în timp, gestionați memorați cache în mod eficient cu ETag și documentați contractul cu OpenAPI 3.1. Acestea sunt adevărații diferențieri între un API profesional și unul care provoacă probleme consumatorilor.
Ce vei învăța
- Cele 4 niveluri ale modelului de maturitate Richardson cu exemple concrete
- Semantică HTTP corectă: metode, coduri de stare, anteturi
- Idempotenta si metode sigure: bazele teoretice cu aplicatii practice
- Strategii de versiuni: URI, antet și versiunea prin modificări aditive
- ETag și solicitări condiționate pentru memorarea în cache eficientă
- OpenAPI 3.1: structura documentului și cele mai bune practici
Modelul de maturitate Richardson: Cele 4 Nivele
Modelul de maturitate Richardson măsoară „RESTfulness” unui API pe o scară 0 la 3. Înțelegerea acestor niveluri ajută la identificarea golurilor arhitecturale în API-urile existente și construiți altele noi la nivelul corect.
Nivelul 0: HTTP ca transport (tunel)
// 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
Nivelul 1: Resurse (URI semnificative)
// 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
Nivelul 2: verbe HTTP (nivelul standard)
// 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
Nivelul 3: HATEOAS (Hypermedia ca motor al stării aplicației)
// 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: Merită?
HATEOAS este teoretic elegant, dar rar implementat în practică. Motivele:
- Mărește semnificativ dimensiunea răspunsului
- Cu toate acestea, clienții adesea „codează” adresele URL pentru performanță
- Necesită instrumente specifice pentru a naviga prin linkuri
- Majoritatea echipelor folosesc în schimb OpenAPI ca contract
Nivelul 2 + OpenAPI 3.1 și punctul ideal pragmatic pentru majoritatea API-urilor în 2026. HATEOAS are sens în principal în API-urile publice unde stabilitatea URL-ului este pe termen lung termen și critică.
Semantică HTTP corectă
Folosirea verbelor HTTP cu semantica corectă nu este doar o problemă estetică: are impact cache, idempotity și capacitatea clienților de a retrage cererile în siguranță.
// 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)
Seif înseamnă că cererea nu are efecte secundare la nivelul serverului (serverul nu își schimbă starea). Un client poate „apăsa F5” pe un GET fără consecințe.
Idempotent înseamnă că mai multe cereri identice produc același lucru rezultatul unei singure cereri. Esențial pentru reîncercări: dacă rețeaua se defectează în timpul unei ștergeri, clientul poate încerca din nou fără teamă de a șterge de mai multe ori.
Coduri de stare: Folosiți-le pe cele potrivite
Abuzul de 200 OK pentru tot (inclusiv erorile corporale) și unul dintre anti-tipare
mai frecvente. Utilizarea codurilor corecte permite clienților, proxy-urilor și instrumentelor de monitorizare
interpretați corect răspunsurile:
// 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: Distincția importantă
Confuzia dintre PUT și PATCH este comună, dar are implicații concrete:
// 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" }
]
Strategii de versiuni
Versiunea este una dintre cele mai importante decizii în proiectarea unui API public. Odată că clienții depind de un API, schimbarea contractului le întrerupe aplicațiile. Le Strategiile principale au diferite compromisuri:
1. Versiune URI (cel mai frecvent)
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. Versiune antet
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. Versiune prin modificări aditive (cel mai bun)
// 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 și solicitări condiționate
L'ETag (Entity Tag) și un mecanism HTTP pentru a gestiona memoria cache și competiție optimistă. Fiecare resursă are un hash sau un marcaj de timp care identifică versiunea sa curent:
// 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
Documentarea cu OpenAPI 3.1
OpenAPI 3.1 este standardul industrial pentru documentarea API-urilor REST. Un document OpenAPI frumos scris servește ca un contract formal, permite generarea SDK-ului clientului și puteri Documentație interactivă cu Swagger UI sau 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: []
Model pentru răspunsuri la eroare
O structură consistentă pentru răspunsurile la erori îmbunătățește dramatic dezvoltatorul Experiența consumatorului API. Standardul RFC 9457 (Detalii despre problemă) și a devenit alegerea preferată în 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
}
Concluzii și pașii următori
Un API REST profesional în 2026 operează la nivelul 2 al modelului de maturitate Richardson (resurse + verbe HTTP corecte + coduri de stare adecvate), utilizați ETag pentru stocarea în cache și concurența optimistă, adoptă versiunea durabilă bazată pe modificări aditive și documentează contractul formal cu OpenAPI 3.1. Nu este necesar să atingeți nivelul 3 HATEOAS în majoritatea contextelor.
Următorul articol examinează GraphQL în profunzime: cum funcționează sistemul de rezolutori, deoarece problema N+1 este cel mai comun risc arhitectural, și ca DataLoader rezolvă gruparea interogărilor bazei de date.
Seria: API Design — Comparație REST, GraphQL, gRPC și tRPC
- Articolul 1: Peisajul API în 2026 — Matricea decizionale
- Articolul 2 (acesta): REST în 2026 — Cele mai bune practici, versiunea și modelul de maturitate Richardson
- Articolul 3: GraphQL — Limbajul de interogare, soluția și problema N+1
- Articolul 4: Federația GraphQL – Supergraph, Subgraph și Apollo Router
- Articolul 5: gRPC — Protobuf, performanță și comunicare de la serviciu la serviciu
- Articolul 6: tRPC — Tip Siguranță End-to-End fără generare de cod
- Articolul 7: Webhooks — Modele, securitate și logică de reîncercare
- Articolul 8: Versiune API - URI, antet și Politica de depreciere
- Articolul 9: Limitarea ratei și limitarea — Algoritmi și implementări
- Articolul 10: Arhitectură API hibridă – REST + tRPC + gRPC în 2026







