# Progettare un'API: principi che reggono la crescita

I principi che reggono la crescita di un'API: risorse al posto di verbi, codici HTTP con un significato solo, errori leggibili da una macchina e contratto versionato prima del codice.

> Pagina: https://ui.eneawork.it/blog/progettare-un-api
> Markdown: https://ui.eneawork.it/blog/progettare-un-api.md

*2026-11-01*

Progettare un'API che regge la crescita segue cinque principi: risorse al posto di verbi, codici HTTP con un significato solo, errori leggibili da una macchina, paginazione e idempotenza progettate prima, contratto versionato. Il resto sono dettagli che si possono cambiare senza rompere i client.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, misurati e letti da /api/stats il 1 novembre 2026. L'endpoint /api/stats è anche il caso verificato: risponde JSON senza autenticazione, con i quattro conteggi usati in questa pagina. La query «api design principles» cresce del 1.900% nell'export Google Trends worldwide del 1 novembre 2026: una variazione relativa, non un volume.

## Risorse, non verbi

Un'API REST espone sostantivi: /orders, /orders/42, /orders/42/items. L'azione sta nel metodo HTTP, non nel percorso. POST /orders/42/cancel è accettabile quando la cancellazione non è una modifica di campo, ma GET /getOrders è un errore di progetto: GET deve essere sicuro e ripetibile, e un verbo nel percorso invita a usarlo per tutto. Il confronto con le server actions è in route handlers e server actions.

## I codici HTTP non sono decorazione

RFC 9110, HTTP Semantics, giugno 2022, definisce il significato dei metodi e degli stati. Usa 201 per una risorsa creata, 204 per un successo senza corpo, 400 per una richiesta malformata, 401 per identità assente, 403 per identità presente senza permesso, 404 per risorsa inesistente, 409 per conflitto di stato, 422 per dati sintatticamente validi ma non accettabili, 429 per troppe richieste. Restituire 200 con {"error": "not found"} obbliga ogni client a leggere il corpo per capire cosa è successo, e rompe cache, retry e monitoraggio.

## Errori che una macchina può leggere

RFC 9457, Problem Details for HTTP APIs, luglio 2023, definisce un corpo di errore standard con type, title, status, detail e instance, servito come application/problem+json. Un client può distinguere un errore di validazione da un errore temporaneo senza analizzare il testo del messaggio. Il campo type è un URI: metti lì la documentazione, non una frase per umani.

## Paginazione: cursore, non offset

?offset=40&limit=20 sembra semplice finché un record viene inserito o cancellato: la pagina successiva salta una riga o la ripete. Un cursore opaco, per esempio ?after=eyJpZCI6NDJ9, indica un punto stabile nell'ordinamento. Restituisci sempre next_cursor e un has_more esplicito: il client non deve dedurre la fine dalla lunghezza della pagina.

## Idempotenza e versioning

Una richiesta POST ripetuta dopo un timeout può creare due ordini. L'header Idempotency-Key, con una chiave generata dal client e conservata per almeno 24 ore, permette al server di restituire la prima risposta invece di eseguire di nuovo. Per il versioning, il numero nella URL (/v1/) è la scelta più leggibile e la più facile da monitorare; la versione nell'header funziona meglio se hai pochi client controllati. In entrambi i casi servono una data di deprecazione e un periodo di doppia esecuzione.

## Il contratto prima del codice

OpenAPI 3.1.0, pubblicato il 15 febbraio 2021, descrive percorsi, schemi e risposte in JSON Schema. Scritto prima dell'implementazione, il contratto permette di generare client, documentazione e test di conformità dallo stesso file. Il comando sotto valida la specifica e verifica che l'endpoint risponda: due controlli che intercettano la maggior parte delle rotture.

npx @redocly/cli lint openapi.yaml curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/v1/orders

## Sicurezza e dati personali

Il regolamento (UE) 2016/679, del 27 aprile 2016, articolo 32, chiede misure adeguate al rischio: autenticazione forte, cifratura in transito, registri di accesso e limiti di frequenza. L'articolo 25 chiede che la minimizzazione sia nel progetto: un endpoint che restituisce l'intero record utente per mostrarne il nome è un problema di progettazione, non di configurazione. Sul lato applicativo, il controllo degli accessi va nel middleware e non nel client; il modello è descritto in middleware di autenticazione.

## Dove questi principi non bastano

Un'API interna chiamata da un solo servizio può usare RPC e non guadagnare nulla da REST. Un flusso in tempo reale richiede WebSocket o Server-Sent Events, dove i codici HTTP non arrivano. E nessun principio risolve la latenza: se una risposta impiega tre secondi, la documentazione perfetta non salva l'esperienza.

## Da dove partire

Scrivi il contratto OpenAPI prima della prima rotta e collegalo alla CI.,Sostituisci i 200 con errori nel corpo con codici di stato corretti, uno per caso.,Aggiungi Idempotency-Key agli endpoint che creano ordini o pagamenti.,Documenta le risposte con una pagina leggibile: le tabelle e i blocchi dashboard coprono i casi più comuni, con shadcn/ui per i controlli.,Approfondisci la cache, che decide metà delle prestazioni di un'API: i quattro livelli di cache in Next.js. Se confronti framework, leggi Remix e Next.js.

## FAQ

### Meglio REST o GraphQL?

Dipende dai client. REST è più semplice da mettere in cache e da monitorare; GraphQL conviene quando molti client chiedono forme di dati diverse e il costo di una query controllata è accettabile. Per un'API pubblica piccola, REST resta la scelta più prevedibile.

### Quando usare POST e quando PUT?

PUT sostituisce una risorsa in un percorso noto ed è idempotente: ripeterlo produce lo stesso stato. POST crea una risorsa o avvia un'azione e non è idempotente, salvo l'uso di una chiave di idempotenza.

### Che differenza c'è tra 401 e 403?

401 significa che manca o non è valida l'autenticazione: il client deve ottenere credenziali. 403 significa che l'identità è nota ma non ha il permesso: ripetere la richiesta non cambia nulla.

### Serve davvero versionare l'API?

Sì, appena hai un client che non aggiorni insieme al server. Il numero nella URL è la forma più leggibile; la versione nell'header riduce il rumore ma richiede più disciplina nel monitoraggio.

### Come gestisco un errore di validazione?

Rispondi 422 con un corpo application/problem+json e un elenco di campi non validi. Non restituire 200 con un messaggio: il client non può distinguere un successo da un rifiuto.
