API REST e retry, come evitare richieste duplicate

6 novembre 2026

Tastiera con neuroni luminosi al posto dei tasti. Un'immagine che evoca la potenza dell'intelligenza artificiale e delle API REST.

Indice

Un client mostra “timeout” dopo aver inviato un ordine e non sa se ripetere la richiesta: con un’API REST ben progettata, la risposta dipende da come l’operazione gestisce i tentativi duplicati. In genere REST usa risorse e semantiche HTTP standard, ma una API che restituisce JSON via HTTP non rispetta automaticamente tutti i vincoli REST.

Schema di comunicazione client-server con metodi HTTP (GET, POST, PUT, DELETE) e formato JSON, tipico di un'API REST.

REST funziona quando l’interfaccia rende prevedibili le richieste

  • Risorsa: un ordine può essere identificato da /orders/123.
  • Metodo: GET legge, POST avvia una creazione, PUT sostituisce e DELETE rimuove secondo semantiche HTTP.
  • Stateless: ogni richiesta porta le informazioni necessarie, senza dipendere dalla memoria della richiesta precedente.
  • Retry: prima di ripetere una scrittura, controlla se l’operazione è idempotente o protetta da una chiave di idempotenza.
  • REST rigoroso: le risposte guidano il client anche tramite link alle azioni successive; molti servizi JSON adottano solo una parte di questa idea.

Una risorsa descrive il dominio, non una tabella del database

Immagina un gestionale che espone ordini e clienti. Un percorso come /orders/123 identifica una risorsa; il verbo HTTP indica cosa fare con la sua rappresentazione. La distinzione è utile perché il client ragiona in termini di ordini, mentre il server può cambiare schema o database senza costringerlo a cambiare insieme a lui.

Nel suo lavoro del 2000, Architectural Styles and the Design of Network-based Software Architectures, Roy Fielding definisce REST come uno stile architetturale basato su vincoli, non come un framework o un formato JSON. Tra questi ci sono client-server, comunicazione stateless, cache, sistema a strati e interfaccia uniforme; quest’ultima comprende risorse identificabili, manipolazione tramite rappresentazioni, messaggi auto-descrittivi e ipermedia come motore dello stato dell’applicazione.

Il punto più trascurato è l’ipermedia: una risposta può includere link che indicano le azioni disponibili, così il client non deve ricostruire ogni URL da regole rigide. Molte API chiamate “REST” si fermano a risorse, JSON e metodi HTTP; possono essere pratiche, ma il nome descrive una versione meno rigorosa dello stile.

GET, PUT e DELETE permettono retry più prevedibili di POST

Un timeout lascia una domanda scomoda: il server ha eseguito l’operazione oppure no? La semantica del metodo aiuta a decidere. La specifica RFC 9110, HTTP Semantics definisce GET come sicuro, cioè senza modifiche richieste allo stato, e GET, PUT e DELETE come idempotenti: ripetere la stessa richiesta non dovrebbe produrre un effetto ulteriore rispetto alla prima esecuzione.

Idempotente non significa che ogni risposta sia identica. Una prima DELETE può riuscire e una successiva restituire “non trovato”; ciò che resta uguale è l’effetto voluto sullo stato. POST, invece, non è idempotente per definizione: due invii di creazione possono generare due ordini distinti. Anche PATCH dipende dalle istruzioni contenute, perché impostare uno stato a “spedito” si comporta diversamente dall’incrementare un contatore.

SituazioneRischioScelta pratica
GET dopo un timeoutLa lettura può essere ripetuta senza chiedere una modifica.Ripeti la richiesta, applicando comunque timeout e limiti di traffico.
PUT con lo stesso contenutoIl client mira a impostare lo stato della risorsa allo stesso valore.Il retry è normalmente sicuro se l’endpoint segue la semantica HTTP.
POST per creare un ordineUn secondo invio può creare un secondo ordine.Usa una chiave di idempotenza gestita dal servizio oppure verifica lo stato prima di riprovare.
PATCH che incrementa un totaleOgni retry potrebbe applicare di nuovo l’incremento.Rendi l’operazione verificabile o proteggila contro la duplicazione.

Una chiave di idempotenza evita il doppio ordine dopo un timeout

Riprendiamo il caso iniziale. Il client invia un POST per creare un ordine, il server salva l’acquisto ma la risposta si perde; senza una protezione, il nuovo invio può creare un altro acquisto. La decisione pratica è semplice: se un retry può generare un secondo effetto, il servizio deve riconoscere la richiesta già elaborata.

Un approccio comune consiste nell’inviare una chiave univoca insieme alla richiesta. Il server associa la chiave al risultato e, se riceve di nuovo la stessa operazione, restituisce il risultato già registrato invece di ripeterla. Perché funzioni anche dopo un riavvio, la registrazione deve essere persistente; inoltre, riutilizzare la chiave con un payload diverso dovrebbe produrre un errore esplicito.

Per una chiamata come POST /orders, la chiave può identificare il tentativo logico di acquisto. Il client la riusa soltanto quando ripete quella stessa operazione, non per un ordine nuovo. Io considero questa protezione una scelta necessaria quando un duplicato ha conseguenze economiche o operative, mentre per una lettura GET aggiunge complessità senza un vantaggio equivalente.

Un endpoint RPC può essere più chiaro quando si invia un comando

Non tutte le operazioni descrivono bene una modifica diretta a una risorsa. “Calcola una previsione”, “esegui una simulazione” o “avvia un’elaborazione” sono comandi: forzarli in una struttura di risorse troppo elaborata può rendere l’interfaccia meno leggibile. In questi casi, un endpoint orientato all’azione o un protocollo RPC può esprimere meglio ciò che il client chiede.

La mia regola di scelta è questa: se il client legge o modifica entità del dominio, come ordini, clienti o fatture, preferisco risorse e metodi HTTP standard; se la chiamata avvia un comando con un risultato o un processo autonomo, valuto un disegno RPC oppure una risorsa che rappresenta l’operazione, per esempio /operations/abc. La coerenza tra endpoint conta più dell’assenza assoluta di verbi negli URL.

Per lavori lunghi, il server può accettare la richiesta e restituire 202 Accepted, insieme a un modo per controllare lo stato. Il client non deve interpretare quel codice come “lavoro completato”: significa che l’elaborazione è stata accettata e proseguirà separatamente. Questa distinzione evita attese interminabili e retry accidentali.

Il contratto API deve sopravvivere ai cambiamenti interni

Una API diventa fragile quando ricalca ogni tabella o proprietà privata del database. Se il client riceve campi che non dovrebbe leggere o può inviare valori che non dovrebbe modificare, l’interfaccia espone troppo del modello interno. Definire modelli di richiesta e risposta separati aiuta a controllare i campi ammessi e a far evolvere il backend senza rompere i consumatori.

La ricerca sull’usabilità delle regole REST offre un’indicazione meno ovvia del semplice “segui le best practice”: uno studio con 105 partecipanti ha confrontato versioni conformi e non conformi di 12 regole di progettazione; per 11 regole, le violazioni hanno ottenuto risultati significativamente peggiori nei compiti di comprensione. Non dimostra che ogni convenzione sia obbligatoria in ogni API, ma suggerisce che incoerenze e ambiguità possono rendere più difficile capire come usarla.

Quando una schermata deve caricare dati correlati, evita di moltiplicare chiamate seriali solo per preservare un modello teorico. Una rappresentazione composta, una query più flessibile o un endpoint specifico per il client possono ridurre il numero di round trip; documenta però il contratto e non legarlo direttamente alla struttura di archiviazione. La scelta più solida è quella che resta comprensibile anche quando il database cambia.

Prima del rilascio, verifica il comportamento che il client può osservare

Un controllo utile non si limita a verificare che ogni endpoint risponda: simula timeout, invii ripetuti, dati non validi e operazioni in corso. Se il client non può distinguere una richiesta accettata da una conclusa, o non sa se un retry è sicuro, il contratto lascia un buco proprio nel momento peggiore.

  • Metodi coerenti: GET non cambia dati; POST, PUT, PATCH e DELETE riflettono l’effetto descritto.
  • Risposte leggibili: usa codici HTTP e messaggi d’errore che permettano al client di scegliere il passo successivo.
  • Retry definito: documenta quali operazioni sono idempotenti e come proteggi quelle che non lo sono.
  • Confine chiaro: valida input e permessi senza esporre direttamente le entità persistite.

Quando la richiesta iniziale è un ordine, la domanda finale resta concreta: un secondo invio rappresenta un altro acquisto oppure lo stesso tentativo? Se il contratto risponde senza lasciare dubbi, l’API è più utile di una collezione di endpoint che porta soltanto l’etichetta REST.

Domande frequenti

Può creare un secondo ordine: POST non è idempotente per definizione. Per riprovare in sicurezza, il client può riusare una chiave univoca e il server può restituire il risultato già registrato per quella richiesta.

Il client invia una chiave che identifica quel tentativo logico di acquisto e la riusa solo per ripetere la stessa operazione. Il server associa la chiave al risultato in modo persistente; se la riceve di nuovo, restituisce il risultato registrato. Riutilizzarla con un payload diverso dovrebbe generare un errore esplicito.

GET è sicuro perché non richiede modifiche allo stato; GET, PUT e DELETE sono idempotenti, quindi ripetere la stessa richiesta non dovrebbe aggiungere effetti. La risposta può cambiare: per esempio, una seconda DELETE può restituire “non trovato” anche se l’effetto voluto resta lo stesso.

Risorse e metodi HTTP standard sono adatti a leggere o modificare entità come ordini, clienti e fatture. Per comandi come avviare una simulazione o un’elaborazione, un endpoint RPC può essere più leggibile; per un processo lungo si può rappresentare l’operazione come risorsa e restituire 202 Accepted con un modo per controllarne lo stato.

Valuta l'articolo

Valutazione: 0.00 Numero di voti: 0

Tag:

rest idempotenza http rpc

Condividi post

Sandro Grasso

Sandro Grasso

Sono Sandro e da 3 anni seguo con curiosità il mondo dell'informatica, dell'intelligenza artificiale e delle soluzioni cloud. Ho iniziato questo percorso perché sono affascinato da come queste tecnologie stiano plasmando il nostro futuro e desidero aiutare chi legge a navigare in questo mondo in continua evoluzione, rendendo concetti complessi accessibili e comprensibili. Sul sito bartolomeoalberico.it, mi impegno a fornire contenuti accurati e aggiornati, verificando le informazioni e organizzandole in modo chiaro per offrire una guida utile e affidabile.

Scrivi un commento