⌨️ Sviluppo web

Progettare un'API REST chiara: risorse, metodi e codici di stato

Come progettare un'API REST chiara: URL basati su risorse, metodi HTTP, codici di stato, errori coerenti, paginazione, versioni e sicurezza di base.

Un'API è un'interfaccia per altri sviluppatori, e come ogni interfaccia può essere intuitiva o frustrante. Un'API ben progettata si capisce leggendo pochi esempi, si comporta in modo prevedibile e fallisce in modo chiaro. Non esiste un'unica forma corretta, ma esistono convenzioni consolidate che rendono la vita più facile a chi la usa e a chi la mantiene.

Pensare per risorse

Nello stile REST, gli URL identificano risorse (cose), mentre i metodi HTTP indicano le azioni. Gli URL contengono quindi nomi, di solito al plurale, e non verbi:

GET    /articoli            elenco degli articoli
POST   /articoli            crea un articolo
GET    /articoli/42         dettaglio dell'articolo 42
PATCH  /articoli/42         modifica parziale
DELETE /articoli/42         eliminazione
GET    /articoli/42/commenti  commenti dell'articolo 42

Da evitare forme come /getArticoli o /articoli/42/elimina: duplicano nell'URL l'informazione che il metodo già porta.

I metodi HTTP e il loro significato

Metodo Uso Sicuro Idempotente
GET leggere sì sì
POST creare o avviare un'operazione no no
PUT sostituire per intero no sì
PATCH modificare in parte no non necessariamente
DELETE eliminare no sì
  • Sicuro significa che non modifica lo stato del server. Una GET non deve mai cancellare o modificare dati: crawler, anteprime dei link e prefetch dei browser eseguono richieste GET in automatico.
  • Idempotente significa che ripetere la richiesta più volte ha lo stesso effetto di farla una sola volta. È importante perché i client, in caso di errore di rete, tendono a ripetere le richieste.

Per le operazioni POST che non devono essere duplicate, come un pagamento o un ordine, un approccio diffuso è accettare una chiave di idempotenza inviata dal client in un header: se arriva due volte la stessa chiave, il server restituisce il risultato della prima richiesta invece di eseguirla di nuovo.

Codici di stato che dicono la verità

Il codice di stato è la prima cosa che il client controlla. Restituire sempre 200 con un campo "errore": true nel corpo costringe ogni client a interpretare il contenuto e rompe strumenti, cache e monitoraggio.

I codici più utili:

  • 200 OK: richiesta riuscita, con contenuto.
  • 201 Created: risorsa creata; includi l'header Location con l'URL della nuova risorsa.
  • 204 No Content: riuscita, senza contenuto (tipico di DELETE).
  • 400 Bad Request: richiesta malformata.
  • 401 Unauthorized: autenticazione mancante o non valida.
  • 403 Forbidden: autenticato, ma senza permesso.
  • 404 Not Found: la risorsa non esiste.
  • 409 Conflict: conflitto con lo stato attuale, per esempio un duplicato.
  • 422 Unprocessable Content: sintassi corretta ma dati non validi.
  • 429 Too Many Requests: limite di frequenza superato.
  • 500 Internal Server Error: errore imprevisto del server.

Errori coerenti e utili

Ogni errore dovrebbe avere la stessa struttura, così il client può gestirli in un unico punto. Esiste anche uno standard IETF per questo scopo, i "Problem Details", con il tipo di contenuto application/problem+json. Un esempio:

{
  "type": "https://api.esempio.it/errori/validazione",
  "title": "Dati non validi",
  "status": 422,
  "errors": [
    { "campo": "email", "messaggio": "Formato non valido" }
  ]
}

Due regole: il messaggio deve aiutare chi integra l'API a capire cosa correggere, e non deve rivelare dettagli interni come query SQL, percorsi dei file o tracce dello stack.

Elenchi: paginazione, filtri e ordinamento

Un elenco non dovrebbe mai restituire tutti gli elementi in un colpo solo. Le due tecniche principali di paginazione:

  • Offset e limite: GET /articoli?limit=20&offset=40. Semplice e permette di saltare a una pagina qualsiasi, ma diventa lenta su tabelle enormi e può saltare o duplicare elementi se i dati cambiano tra una richiesta e l'altra.
  • Cursore: GET /articoli?limit=20&dopo=eyJpZCI6MTIzfQ. Il server restituisce un cursore opaco per la pagina successiva. È stabile e efficiente, ma non permette di saltare direttamente alla pagina 37.
{
  "dati": [ ... ],
  "pagina_successiva": "/articoli?limit=20&dopo=eyJpZCI6MTQzfQ"
}

Filtri e ordinamento si esprimono con parametri di query leggibili: ?stato=pubblicato&ordina=-data. Imposta sempre un limite massimo lato server per limit, per evitare richieste che chiedono un milione di righe.

Versioni

Prima o poi un cambiamento romperà la compatibilità. Le strategie comuni sono la versione nell'URL (/v1/articoli) o in un header. La versione nell'URL è la più semplice da capire e da provare. Qualunque scelta tu faccia:

  • aggiungere campi nuovi alle risposte di solito non rompe nulla;
  • rimuovere o rinominare campi, o cambiarne il tipo, richiede una nuova versione;
  • annuncia con anticipo le dismissioni e mantieni per un periodo ragionevole la versione precedente.

Sicurezza di base

  • Solo HTTPS, sempre.
  • Autenticazione tramite token inviati nell'header Authorization, mai nei parametri dell'URL, che finiscono nei log.
  • Controllo delle autorizzazioni su ogni risorsa: verificare che l'utente sia autenticato non basta, bisogna verificare che l'articolo 42 sia suo. È uno degli errori più comuni nelle API.
  • Validazione rigorosa dell'input e limiti di frequenza.
  • Risposte che includono solo i campi necessari: non restituire l'intero record del database "per comodità".

Documentazione

Un'API senza documentazione è un'API che nessuno sa usare. Una specifica OpenAPI descrive endpoint, parametri e risposte in un formato leggibile da persone e strumenti, e permette di generare documentazione interattiva e client.

In sintesi

  • Usa URL basati su risorse e lascia ai metodi HTTP il compito di indicare l'azione.
  • Rispetta sicurezza e idempotenza dei metodi; GET non deve mai modificare dati.
  • Restituisci codici di stato veritieri ed errori con struttura coerente e senza dettagli interni.
  • Pagina sempre gli elenchi e fissa un limite massimo lato server.
  • Verifica le autorizzazioni su ogni singola risorsa e documenta l'API con esempi.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche