Discuțiile despre versionarea API încep aproape întotdeauna de la capătul greșit, adică de la locul în care se pune numărul versiunii. Este cea mai lipsită de consecințe decizie din tot subiectul. Ceea ce contează este care modificări cer de fapt o versiune nouă, iar majoritatea echipelor greșesc în direcția nepăsării: livrează ceva ce consideră pur aditiv, și un client se rupe.

Modelul mental util este că API-ul vostru este o promisiune despre ceea ce un apelant se poate baza. O modificare rupe compatibilitatea dacă invalidează ceva pe care un apelant rezonabil se baza, iar apelanții se bazează pe mai mult decât le permite documentația voastră.

Modificarea care îi prinde pe toți: adăugarea unui câmp într-un răspuns. Este aditivă, nu poate strica un client scris corect și strică totuși clienți reali în mod regulat, pentru că unii dintre ei validează răspunsurile strict și resping câmpurile necunoscute. Dacă vina este a voastră sau a lor nu mai are nicio importanță din momentul în care integrarea lor este căzută și sună telefonul.


Ce înseamnă cu adevărat o rupere de compatibilitate

Rupe fără niciun dubiu: eliminarea sau redenumirea unui câmp, schimbarea tipului unui câmp, adăugarea unui parametru obligatoriu la cerere, înăsprirea validării, schimbarea sensului unei valori existente sau schimbarea unui cod de stare pe care un apelant își ramifică logica.

Rupe în practică, deși pare sigur: adăugarea unui câmp într-un răspuns, atunci când clienții validează strict. Schimbarea ordinii unui tablou care nu fusese niciodată promisă, dar pe care apelanții au presupus-o. Schimbarea unui mesaj de eroare al cărui text cineva îl compară ca șir de caractere. Transformarea unei operații sincrone în una asincronă.

Cu adevărat sigur: adăugarea unui nou parametru opțional de cerere, adăugarea unui nou endpoint, relaxarea validării și adăugarea unei valori noi într-o enumerare, dar numai dacă li s-a spus clienților de la bun început să se aștepte la valori necunoscute și puteți verifica faptul că le tratează.

Tiparul este că siguranța depinde de ceea ce fac efectiv apelanții, nu de ceea ce permite specificația. Dacă controlați fiecare client, puteți verifica. Dacă nu, presupuneți că cineva se bazează exact pe lucrul pe care îl credeați lipsit de importanță, pentru că așa stau lucrurile.

Strategii de versionare API și cât costă fiecare

Versiunea în URL. Abordarea cea mai răspândită, iar calitatea ei este că e evidentă: /v1/orders și /v2/orders sunt resurse vizibil diferite. Costul este că încurajează salturi de versiune pentru întregul API, așa că o modificare care atinge un singur endpoint trage totul după ea, iar clienții trebuie să migreze dintr-o dată.

Versiunea într-un header. Păstrează URL-urile stabile și permite o granularitate mai fină, cu prețul invizibilității. Nimeni nu vede versiunea în browser sau într-o linie de log fără să o caute, iar un apelant care omite headerul primește valoarea voastră implicită, ceea ce este o decizie pe care trebuie să o luați în mod deliberat.

Versionarea după dată. Un apelant se fixează pe o dată și primește API-ul așa cum se comporta atunci. Stripe documentează această abordare, în care fiecare cont are o versiune implicită, iar cererile o pot suprascrie individual. Oferă cei mai mici pași de migrare posibili și mută povara compatibilității în propria voastră bază de cod, care întreține de acum transformări între versiuni.

Fără versionare, doar modificări aditive. Viabilă și subestimată atunci când vă puteți angaja sincer să nu eliminați niciodată nimic. Costul îl reprezintă câmpurile pe care nu le mai puteți șterge și comportamentele pe care nu le mai puteți corecta, adică o taxă lentă în loc de o factură bruscă.

Nu există un răspuns corect, ci doar un schimb între povara voastră de migrare și cea a clienților voștri. Versionarea după dată este cea mai blândă cu apelanții și cea mai scumpă de întreținut. Versionarea în URL este exact pe dos.

Cum faci suportabile modificările care rup

Întâi extinde, apoi restrânge. Adăugați câmpul nou alături de cel vechi. Populați-le pe amândouă. Dați clienților timp să se mute. Eliminați-l pe cel vechi într-o versiune ulterioară. Astfel o modificare care rupe devine două modificări sigure, iar pasul în plus merită aproape de fiecare dată.

Măsurați cine ce folosește. Nu puteți retrage o versiune în siguranță fără să știți cine stă pe ea. Înregistrați la fiecare cerere versiunea și identitatea clientului, pentru ca deprecierea să devină o discuție bazată pe dovezi, nu un anunț aruncat în întuneric.

Anunțați printr-un mecanism, nu doar printr-un email. Headerele de răspuns Deprecation și Sunset permit unui client să descopere data retragerii în mod programatic, ceea ce are șanse mai mari să fie observat decât un mesaj trimis la o adresă pe care nu o mai citește nimeni.

Dați o fereastră realistă. Integrările sunt întreținute de oameni cu alte priorități, iar un termen mai scurt decât ciclul lor de livrare va fi pur și simplu ratat. Șase luni este ceva obișnuit pentru un API public; mai puțin este rezonabil pentru un grup mic de parteneri cunoscuți cu care ați vorbit.

Retragerea unei versiuni vechi

Măsurarea descrisă mai sus este cea care face posibil acest pas. Anunțați data, urmăriți cum scade traficul și contactați pe nume apelanții care nu s-au mutat.

Așteptați-vă la o coadă lungă. Vor exista integrări despre care nimeni din firma clientului nu mai știe că îi aparțin, iar ele vor fi descoperite în momentul în care opriți versiunea. Întreruperile scurte ajută aici: dezactivați pentru puțin timp versiunea veche la ore anunțate înainte de data finală, astfel încât căderea să se producă atunci când cineva o așteaptă, nu în mijlocul unei perioade aglomerate.

Poziția onestă este că unii apelanți se vor muta doar când versiunea veche va înceta să funcționeze. Planificați pentru asta în loc să vă lăsați surprinși și asigurați-vă că modul de eșec este o eroare clară, care explică ce s-a întâmplat, nu un timeout.

Versiunea de care nu aveți nevoie

Majoritatea API-urilor interne nu au deloc nevoie de versionare, pentru că voi controlați fiecare apelant și puteți schimba ambele părți odată. Să adăugați negociere de versiune la o interfață folosită de două dintre serviciile voastre este mecanică ce vă costă ceva și nu vă apără de nimic.

Momentul în care devine necesară este cel în care nu mai puteți implementa toți consumatorii în același timp, fie pentru că aparțin altei echipe, altui ciclu de livrare sau altei companii. Acesta este declanșatorul real și nu are nicio legătură cu cât de public este API-ul. Considerațiile de proiectare din ghidul nostru de API serverless se aplică la fel și la marginea rețelei.

Mecanik proiectează și întreține API-uri de acest fel ca parte a activității noastre de dezvoltare software. Schema de versionare este rareori decizia interesantă; a ști care dintre apelanții voștri este încă pe cea veche este întotdeauna.



Întrebări frecvente

Ce contează drept modificare de API care rupe compatibilitatea? Eliminarea sau redenumirea unui câmp, schimbarea tipului unui câmp, adăugarea unui parametru obligatoriu, înăsprirea validării, schimbarea sensului unei valori sau schimbarea unui cod de stare pe care apelanții își ramifică logica. Rup și în practică: adăugarea unui câmp în răspuns când clienții validează strict, schimbarea ordinii unui tablou pe care apelanții o presupuneau și modificarea textului unui mesaj de eroare pe care cineva îl compară.

Pun versiunea API în URL sau într-un header? Versionarea în URL este vizibilă și simplă, dar încurajează salturi pentru întregul API și obligă clienții să migreze totul dintr-o dată. Versionarea prin header păstrează URL-urile stabile și permite o granularitate mai fină, dar este invizibilă în loguri și în browser și cere o valoare implicită aleasă deliberat pentru apelanții care o omit. Niciuna nu este greșită; ele schimbă povara voastră de migrare cu cea a clienților voștri.

Ce este versionarea API după dată? Un apelant se fixează pe o dată și primește API-ul așa cum se comporta atunci, așa cum face Stripe cu o versiune implicită per cont pe care cererile individuale o pot suprascrie. Oferă clienților cei mai mici pași de migrare posibili și mută povara compatibilității în baza voastră de cod, care întreține apoi transformările între versiuni.

Cât ar trebui să dureze o fereastră de depreciere a unui API? Șase luni este ceva obișnuit pentru un API public, iar mai puțin este rezonabil pentru un grup mic de parteneri cunoscuți cu care ați vorbit direct. Integrările sunt întreținute de oameni cu alte priorități, așa că o fereastră mai scurtă decât ciclul lor de livrare va fi ratată indiferent cât de clar a fost anunțată.

API-urile interne au nevoie de versionare? De obicei nu, pentru că voi controlați fiecare apelant și puteți schimba ambele părți odată. Versionarea devine necesară în punctul în care nu mai puteți implementa toți consumatorii în același timp, fie că aparțin altei echipe, altui ciclu de livrare sau altei companii. Acela este declanșatorul, nu faptul că API-ul este public.