Usa i metodi HTTP secondo la loro semantica definita
Mappa le operazioni sul metodo la cui semantica corrisponde: GET per il recupero safe, PUT e DELETE per scritture idempotenti, POST per creazioni non idempotenti, PATCH per aggiornamenti parziali. Rispettare questi contratti permette a cache, proxy e client di ragionare sulle richieste e di ritentarle in sicurezza.
- Fai:
POST /ordersper creare, poiGET /orders/{id}per rileggerlo. - Non fare: usare
GET /orders/{id}/deleteper mutare lo stato - un metodo safe non deve mai cambiare nulla.
Restituisci lo status code semanticamente corretto
Usa lo status code come segnale primario di successo/fallimento: 201 per creato, 204 per nessun contenuto, 400/422 per input non valido, 401/403 per l'auth, 404 per mancante, 409 per conflitto, 429 per i rate limit, 5xx per i guasti del server. Client e intermediari generici dipendono dal codice, non dal parsing del testo.
- Fai: restituire
409 Conflictquando viene violato un vincolo di unicità in creazione. - Non fare: restituire
200 OKcon{"error": "..."}nel body - nasconde il fallimento a ogni strumento.
Standardizza i body di errore con Problem Details
Adotta RFC 9457 application/problem+json così ogni errore ha la stessa forma type, title, status, detail e instance più campi di estensione stabili. Un contratto di errore uniforme permette a un solo percorso di codice client di gestire i fallimenti di ogni endpoint.
- Fai: restituire
{"type": "https://errors.example.com/out-of-stock", "title": "Out of stock", "status": 409, "detail": "SKU-42 ha 0 unità"}. - Non fare: inventare una forma JSON di errore ad hoc diversa per ogni endpoint.
Versiona l'API e rompi solo in una nuova major
Scegli uno schema di versioning (URI come /v1, o media type) e mantieni le modifiche dentro una versione major retrocompatibili: aggiungi campi ed endpoint opzionali, non rimuovere o rinominare mai. I client scritti su una versione major devono continuare a funzionare finché non la ritiri deliberatamente.
- Fai: aggiungere un nuovo campo opzionale
currencya una risposta dentrov1. - Non fare: cambiare
amountda numero a oggetto dentrov1- rompe ogni parser esistente.
Comunica la deprecazione prima della rimozione
Quando un endpoint o un campo sta per sparire, segnalalo per tempo con gli header Deprecation e Sunset (RFC 9745, RFC 8594), pubblica una guida di migrazione e mantieni il vecchio comportamento per una finestra dichiarata. Rimuovere qualcosa che i client chiamano ancora, senza preavviso, è il modo più rapido per rompere le integrazioni.
- Fai: restituire
Deprecation: trueeSunset: Wed, 31 Dec 2026 23:59:59 GMTpiù unLinkalla guida di migrazione. - Non fare: cancellare in silenzio
/v1/legacy-reporte lasciare che i chiamanti lo scoprano dai404.
Rendi ripetibili in sicurezza le operazioni non safe con chiavi di idempotenza
Le reti perdono le risposte, quindi i client ritentano; assicurati che una creazione ripetuta non agisca due volte accettando una Idempotency-Key fornita dal client. Memorizza la chiave con la sua prima risposta per una finestra limitata e restituisci quella risposta in caso di ripetizione.
- Fai: accettare
Idempotency-Key:suPOST /paymentse deduplicare su di essa. - Non fare: assumere che il client non re-invii mai un
POST- lo farà, dopo qualsiasi timeout.
Per default usa la paginazione a cursore per le collezioni
Restituisci le collezioni in pagine limitate e preferisci la paginazione a cursore (keyset) così i risultati restano corretti e veloci anche mentre i dati cambiano. Limita sempre la dimensione massima di pagina ed esponi il cursore o i link successivi in modo coerente.
- Fai: rispondere con
{"data": [...], "next_cursor": "eyJpZCI6..."}e accettare?after=.&limit=20 - Non fare: restituire un array illimitato di ogni riga, o usare offset grandi che fanno table-scan.
Valida e limita tutto l'input al confine
Tratta ogni richiesta come non fidata: valida tipi, intervalli, lunghezze e valori enum prima di elaborare, e rifiuta rapidamente l'input malformato con un chiaro 400/422. Limita dimensioni di array, lunghezze di stringa e dimensioni di pagina così una sola richiesta non possa esaurire le risorse.
- Fai: rifiutare
limit=100000con400e un messaggio che indica il massimo consentito. - Non fare: passare input grezzo del client direttamente in una query o in una chiamata a valle.
Autentica e autorizza a ogni richiesta, lato server
Poiché REST è stateless, ogni richiesta deve portare le credenziali, e il server deve verificarle ogni volta - valida firma, exp, iss e aud di un bearer token - poi autorizza separatamente l'azione specifica sulla risorsa specifica. Non fidarti mai di un ruolo o ID asserito dal client.
- Fai: verificare che
token.subpossiedaorder/{id}prima di restituirlo, rispondendo403altrimenti. - Non fare: affidarti al client che nasconde un pulsante, o a un flag
is_admininviato dal client.
Servi solo su TLS
Esponi l'API esclusivamente su HTTPS così credenziali, token e payload non possano essere intercettati o manomessi, e rifiuta l'HTTP in chiaro. Richiedi TLS moderno (1.2+) e valuta HSTS per prevenire il downgrade.
- Fai: reindirizzare o rifiutare
http://e inviareStrict-Transport-Security. - Non fare: accettare token su una connessione non cifrata "solo per test" in produzione.
Applica i rate limit e mostrali negli header
Proteggi il servizio con rate limit per-client, rifiuta l'eccesso con 429 e rendi i limiti visibili tramite RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset e Retry-After. Limiti prevedibili permettono ai client ben educati di auto-limitarsi invece di essere colti di sorpresa.
- Fai: restituire
429conRetry-After: 30quando il bucket è vuoto. - Non fare: scartare in silenzio o lasciare appese le richieste oltre il limite, lasciando i client a indovinare.
Progetta API-first da un contratto scritto
Scrivi l'OpenAPI (o lo schema .proto/GraphQL) prima di implementare, rivedilo con i consumatori e genera documentazione, mock, SDK e contract test da esso. Il contratto diventa la fonte unica di verità e permette ai team client e server di lavorare in parallelo.
- Fai: tenere
openapi.yamlsotto version control e far fallire la CI se l'implementazione diverge da esso. - Non fare: scrivere a mano una documentazione a posteriori che lentamente diverge da ciò che il codice restituisce davvero.
Mantieni i nomi delle risorse coerenti e basati su sostantivi
Usa sostantivi plurali per le collezioni, una sola convenzione di casing e i verbi HTTP (non verbi nel path) per le azioni, ed evita di annidare più di uno o due livelli. La coerenza rende l'API indovinabile e riduce la documentazione che un client deve leggere.
- Fai:
GET /customers/{id}/orderseGET /orders?customerId={id}in modo coerente. - Non fare: mescolare
/getCustomer,/Customers/e/customer_listnella stessa API.
Usa gli ETag per caching e controllo di concorrenza
Restituisci un ETag per le risorse cacheable così i client possono rivalidare con If-None-Match (ottenendo un 304 economico) e aggiornare in sicurezza con If-Match, che rifiuta le scritture obsolete con 412. Questo riduce la banda e previene gli aggiornamenti persi senza lock lato server.
- Fai: emettere
ETag: "v7"e rifiutare unPUTil cuiIf-Matchnon corrisponde alla versione corrente. - Non fare: lasciare che due aggiornamenti concorrenti sovrascrivano in silenzio le rispettive modifiche.