
Quindi, quanto può essere difficile gestire le versioni di un'API? La verità è che non è così difficile, ma ciò che è complicato è mantenere un po' di sanità mentale evitando di cadere inutilmente in un numero vertiginoso di versioni e sotto-versioni applicate a dozzine di endpoint API con compatibilità poco chiare.
Business in a box.
Scopri le nostre soluzioni.
Parla con il nostro team di vendita
I Cambiamenti Bruschi sono Male! API Versioning Buono!
Come chiunque abbia costruito o utilizzi regolarmente un API si rende conto prima o poi, le modifiche dirompenti sono molto gravi e possono essere un serio difetto in un API altrimenti utile. Una modifica dirompente è un cambiamento nel comportamento di un API che può interrompere l'integrazione di un utente e portare a molta frustrazione e perdita di fiducia tra il fornitore dell'API e l'utente. Le modifiche dirompenti richiedono che gli utenti siano notificati in anticipo (con i relativi mea culpa) piuttosto che un cambiamento che appare semplicemente, come una nuova funzione deliziosa. Il modo per evitare quella frustrazione è versionare un API con garanzie da parte del proprietario dell'API che non ci saranno cambiamenti sorprendenti introdotti entro una singola versione.
Quindi quanto può essere difficile versionare un API? La verità è che non lo è, ma ciò che è difficile è mantenere un po' di sanità mentale senza inutilmente degenerare in un numero vertiginoso di versioni e sotto-versioni applicate su dozzine di endpoint API con compatibilità poco chiare.
Abbiamo introdotto v1 dell'API tre anni fa e non ci siamo resi conto che sarebbe stata in forte uso fino ad oggi. Quindi come abbiamo continuato a fornire il miglior API di consegna email per oltre due anni mantenendo ancora la stessa versione di API? Mentre ci sono molte opinioni diverse su come versionare le REST API, spero che la storia del nostro umile ma potente v1 possa guidarti sulla tua strada verso l'illuminazione sulla versioning delle API.
REST È Best
API Governance
Con una convenzione di versioning selezionata avevamo più domande. Quando avremmo dovuto aumentare la versione? Cos'è un cambiamento radicale? Dovremmo revisionare l'intero API o solo determinati endpoint? In SparkPost, abbiamo più team che lavorano su diverse parti del nostro API. All'interno di quei team, le persone lavorano su diversi endpoint in momenti diversi. Pertanto, è molto importante che il nostro API sia coerente nell'uso delle convenzioni. Questo era più grande del versioning.
Abbiamo istituito un gruppo di governance, inclusi ingegneri che rappresentano ogni team, un membro del team di Product Management, e il nostro CTO. Questo gruppo è responsabile di stabilire, documentare e far rispettare le nostre convenzioni API su tutti i team. Un canale di governance API su Slack è anche utile per vivaci dibattiti sull'argomento.
Il gruppo di governance ha identificato diversi modi in cui le modifiche possono essere introdotte nel API che sono vantaggiose per l'utente e non costituiscono un cambiamento radicale. Questi includono:
Una nuova risorsa o un nuovo endpoint API
Un nuovo parametro opzionale
Un cambiamento a un endpoint API non pubblico
Una nuova chiave opzionale nel corpo POST JSON
Una nuova chiave restituita nel corpo della risposta JSON
Al contrario, un cambiamento radicale includeva qualsiasi cosa potesse interrompere l'integrazione di un utente come:
Un nuovo parametro richiesto
Una nuova chiave richiesta nei corpi POST
Rimozione di un endpoint esistente
Rimozione di un metodo di richiesta endpoint esistente
Un comportamento interno materialmente diverso di una chiamata API – come un cambiamento del comportamento predefinito.
The Big 1.0
Mentre documentavamo e discutevamo queste convenzioni, siamo giunti alla conclusione che era nell'interesse di tutti (incluso il nostro!) evitare di apportare modifiche significative all’API poiché gestire più versioni aggiunge un bel po’ di lavoro extra. Abbiamo deciso che c'erano alcune cose che avremmo dovuto sistemare con la nostra API prima di impegnarci con "v1".
Inviare una semplice email richiedeva troppo sforzo. Per "mantenere semplici le cose semplici" abbiamo aggiornato il corpo dell'POST per garantire che siano soddisfatti sia i casi d'uso semplici che quelli complessi. Il nuovo formato era anche più a prova di futuro. In secondo luogo, abbiamo affrontato un problema con il punto finale dei Metrics. Questo punto finale utilizzava un parametro "group_by" che avrebbe modificato il formato del corpo della risposta GET in modo tale che la prima chiave fosse il valore del parametro group by. Non sembrava molto RESTful, quindi abbiamo suddiviso ciascun group by in un endpoint separato. Infine, abbiamo verificato ogni endpoint e apportato piccoli cambiamenti qua e là per garantire che fossero conformi agli standard.
Documentazione Accurata
È importante avere documentazione API accurata e utilizzabile per evitare modifiche incompatibili, sia deliberate che accidentali. Abbiamo deciso di utilizzare un semplice approccio alla documentazione API sfruttando un linguaggio Markdown chiamato API Blueprint e gestire i nostri documenti in Github. La nostra comunità contribuisce e migliora questi documenti open source. Manteniamo inoltre un set di documenti non pubblici in Github per le API interne e gli endpoint.
Inizialmente, abbiamo pubblicato i nostri documenti su Apiary, un ottimo strumento per prototipare e pubblicare documenti API. Tuttavia, incorporare Apiary nel nostro sito web non funziona sui dispositivi mobili, quindi ora utilizziamo Jekyll per generare documenti statici. I nostri ultimi SparkPost API docs ora si caricano rapidamente e funzionano bene sui dispositivi mobili, il che è importante per gli sviluppatori che non sono sempre seduti al computer.
Separare Deployment da Release
Abbiamo imparato presto il prezioso trucco di separare un deployment da un rilascio. In questo modo è possibile distribuire frequentemente modifiche quando sono pronte attraverso consegna e distribuzione continue, ma non le annunciamo sempre pubblicamente o le documentiamo allo stesso tempo. Non è raro per noi distribuire un nuovo endpoint API o un miglioramento a un endpoint API esistente e utilizzarlo dall'interno dell'interfaccia utente o con strumenti interni prima di documentarlo pubblicamente e supportarlo. In questo modo possiamo apportare alcune modifiche per la facilità d'uso o la conformità agli standard senza preoccuparci di creare un temuto cambiamento che rompa. Una volta che siamo soddisfatti del cambiamento, lo aggiungiamo alla nostra documentazione pubblica.
Accidenti!
È giusto ammettere che ci sono stati momenti in cui non siamo stati all'altezza dei nostri ideali di “nessun cambiamento interrompente” e questi meritano di essere appresi. In un'occasione abbiamo deciso che sarebbe stato meglio per gli utenti se una certa proprietà di default fosse stata impostata su true invece che su false. Dopo aver implementato la modifica, abbiamo ricevuto diverse lamentele dagli utenti poiché il comportamento era cambiato inaspettatamente. Abbiamo ripristinato la modifica e aggiunto un'impostazione a livello di account – un approccio sicuramente più user-friendly.
Occasionalmente siamo tentati di introdurre cambiamenti interrompenti come risultato di correzioni di bug. Tuttavia, abbiamo deciso di lasciare queste idiosincrasie inalterate piuttosto che rischiare di rompere le integrazioni dei clienti per il bene della coerenza.
Ci sono rari casi in cui abbiamo preso la seria decisione di apportare un cambiamento interrompente – come ad esempio deprecare una risorsa o un metodo API – nell'interesse della comunità di utenti più ampia e solo dopo aver confermato che c'è un impatto minimo o nullo sugli utenti. Ad esempio, abbiamo deliberatamente scelto di modificare il comportamento della risposta della Suppression API, ma solo dopo aver attentamente valutato i benefici e gli impatti per la comunità e comunicato attentamente la modifica ai nostri utenti. Tuttavia, non introdurremmo mai una modifica che abbia una remota possibilità di influire direttamente sull'invio della email di produzione di un utente.