Modifiche alle API

Changelog dei webhook: il breaking change non richiesto

6 min di lettura

Un changelog di API REST esiste perché un chiamante può scegliere di rifiutare una risposta che non capisce, o almeno registrare un errore abbastanza rumoroso perché qualcuno se ne accorga. Un destinatario di webhook raramente fa nessuna delle due cose. Riceve un POST, legge i campi che si aspetta, e se un campo si è spostato, ha cambiato tipo o è sparito, l’endpoint o crasha in silenzio dentro un job in background che nessuno controlla o, peggio, continua a funzionare con un valore sbagliato che non ha mai validato. Cos’è un breaking change copre la definizione generale; un payload di webhook ha bisogno della propria risposta, perché la modalità di fallimento è diversa da quella di un endpoint che qualcuno chiama di proposito.

Perché un cambiamento nel payload di un webhook si rompe diversamente da un cambiamento nella risposta di un’API?

Perché la direzione della richiesta è invertita. Chi chiama via REST avvia la chiamata e può aggiungere un header di versione, ritentare su un 4xx o leggere un avviso di deprecazione nella risposta. Un destinatario di webhook non ha avviato niente di tutto questo: il vostro server ha deciso di inviare, ha deciso quando, e ha deciso quale forma avrebbe avuto il corpo. L’unica leva del destinatario è la validazione che ha scritto quando l’integrazione è stata costruita, e la maggior parte delle integrazioni si costruiscono una volta, funzionano, e nessuno le rivede più finché non si rompono. Questa asimmetria è l’intero motivo per cui un cambiamento nel payload di un webhook merita più cautela dello stesso cambiamento in un corpo di risposta che un chiamante ha richiesto attivamente.

Cosa conta davvero come breaking change in un payload di webhook?

CambiamentoBreaking per la maggior parte dei destinatari
Aggiungere un nuovo campoNo, se i destinatari ignorano i campi sconosciuti (verificate questa assunzione, non datela per scontata)
Rimuovere un campoSì, se qualcosa lo legge
Rinominare un campoSì, funzionalmente identico a rimuovere quello vecchio
Cambiare il tipo di un campo (stringa a oggetto)Sì, quasi sempre
Riordinare i campi nel corpo JSONNo, per qualsiasi destinatario che analizza per chiave, che dovrebbero essere tutti
Cambiare il nome o tipo dell’eventoSì, se i destinatari filtrano o instradano su di esso

La riga “aggiungere un campo è sicuro” è quella su cui i team fanno più affidamento e quella che vale di più verificare, non assumere. Un parser JSON permissivo ignora i campi sconosciuti per default, ma un destinatario che deserializza in uno schema rigido, diversi linguaggi tipizzati lo fanno senza configurazione extra, può rifiutare l’intero payload appena appare un campo inaspettato. Aggiungere un campo è sicuro per il vostro webhook solo se sapete come analizzano i destinatari, non perché JSON in sé sia permissivo.

Come si versiona un payload di webhook?

Più o meno come per una risposta API, con una differenza: il destinatario non invia mai una richiesta, quindi non può chiedere una versione, ed è il mittente a doverla dichiarare. Può stare nel corpo o in un header della richiesta di consegna stessa; le consegne di GitHub portano X-GitHub-Event e X-GitHub-Hook-ID, e la specifica Standard Webhooks mette i suoi metadati negli header webhook-*. Un campo di versione nel payload ("payload_version": 2) è l’opzione più economica e funziona quando i destinatari sono disposti a diramarsi su di esso. Un tipo di evento versionato (invoice.updated diventa invoice.updated.v2 come evento distinto a cui un destinatario si iscrive volontariamente) richiede più lavoro da costruire ma significa che la forma vecchia continua ad arrivare a chi non ha mai migrato, il che conta di più qui che per un endpoint REST perché non potete chiamare ogni destinatario per dirgli di aggiornare. Un’impostazione per sottoscrizione, scelta alla registrazione dell’endpoint del webhook, anticipa la decisione invece di diramarsi a ogni consegna, ed è la scelta giusta quando avete già un record di sottoscrizione a cui attaccarla.

POST /endpoint-destinatario
{
  "event": "invoice.updated",
  "payload_version": 2,
  "data": { "invoice_id": "inv_123", "status": "paid" }
}

Come fai anche solo a sapere chi sta ascoltando?

Peggio della versione equivalente di questo problema in un changelog di API, perché un webhook non ha un log delle richieste in entrata dalla vostra parte che nomini il chiamante; avete solo il vostro log di consegna in uscita, che vi dice che un endpoint ha ricevuto un 200, non cosa ne ha fatto del corpo. Tracciate almeno due cose: ogni endpoint registrato con una responsabile, la stessa disciplina che i changelog di API interne raccomandano per i consumatori interni, e il vostro tasso di fallimento della consegna per endpoint dopo un cambiamento di payload. Un picco di risposte 4xx o 5xx da un endpoint subito dopo un cambiamento è la cosa più vicina a uno stack trace che otterrete, e spesso è l’unico segnale che un destinatario si è rotto, perché il team che lo gestisce potrebbe non accorgersene per giorni.

Un changelog dei webhook dovrebbe essere separato dal changelog delle API?

Una sezione separata sulla stessa pagina, non una pubblicazione separata. Un changelog di API stabilisce già chi lo legge e come ci si iscrive; un cambiamento nel payload di un webhook appartiene allo stesso feed, etichettato con chiarezza sufficiente perché una sviluppatrice lato destinatario che cerca “questo influisce sulla mia integrazione” possa filtrarlo, perché una consumatrice di webhook spesso non ha altro motivo per controllare un changelog generale di API e lo troverà solo se qualcuno la indirizza lì direttamente.

Come dovrebbe essere una finestra di deprecazione ragionevole per un payload di webhook?

Più lunga della deprecazione REST equivalente, perché la migrazione lato destinatario di solito significa che un secondo team, con cui magari non avete un contatto diretto, deve accorgersene, pianificarla e rilasciarla senza una propria urgenza. Un mese è un minimo ragionevole per un campo che il destinatario sta plausibilmente ancora analizzando con una libreria permissiva; tre mesi o più sono più sicuri per una rimozione di campo che uno schema rigido rifiuterebbe del tutto. Inviate la forma vecchia e quella nuova insieme durante la finestra quando fattibile (il vecchio campo status e il suo sostituto della versione 2 nello stesso payload), perché un destinatario che legge il campo vecchio continua a funzionare senza toccare il codice, e uno che ha già migrato ignora semplicemente il campo di cui non ha più bisogno.

FAQ

I consumatori di webhook devono confermare un cambiamento di payload prima che venga rilasciato? Non esiste un meccanismo di conferma di default, ed è proprio per questo che la finestra di deprecazione conta di più qui che per un’API REST: nessuno conferma di essere pronto, quindi la finestra deve essere abbastanza lunga da far migrare la maggior parte dei destinatari secondo i propri tempi prima che la forma vecchia scompaia.

È mai sicuro aggiungere campi sconosciuti senza preavviso? Solo dopo aver verificato, non assunto, che i vostri destinatari analizzano in modo permissivo. Una voce di changelog costa poco e toglie l’incertezza; aggiungere campi in silenzio assumendo che “i parser JSON ignorano gli extra” rompe qualsiasi destinatario con deserializzazione rigida.

Qual è il modo più veloce per rilevare un destinatario di webhook rotto dopo un cambiamento di payload? Un tasso di fallimento della consegna per endpoint, osservato nelle ore subito dopo il cambiamento. Non vi dirà cosa si è rotto, solo che qualcosa si è rotto, ma è il segnale più precoce e spesso l’unico che otterrete.

La logica di retry aiuta i destinatari a sopravvivere a un cambiamento di payload? No. Un retry rinvia lo stesso nuovo payload; non torna a una forma che il destinatario può analizzare. Un cambiamento di payload rompe un destinatario alla prima consegna e a ogni retry successivo in modo identico.


Le affermazioni tecniche di questo articolo non sono state verificate in modo indipendente. Se qualcosa non è corretto, faccelo sapere e lo correggeremo.

Correlati su changeloop: Documentazione per sviluppatori, Strumenti di changelog a confronto

changeloop
Il team che costruisce un changelog che chiude il cerchio. I tuoi utenti chiedono, il tuo team rilascia, chi ha chiesto lo viene a sapere.