Cele mai bune practici de versionare API, pentru apelanți
8 min de citit
Versionarea API-ului e practica de a menține un contract vechi funcțional după ce l-ați schimbat, ca apelanții să poată avansa după propriul lor program, nu al vostru. Acea propoziție conține cele două decizii care contează: ce contează ca schimbare a contractului, și cât timp continuă să funcționeze cel vechi. Unde trăiește numărul versiunii, despre ce e majoritatea dezbaterilor de versionare, e cel mai puțin important din cele trei și cel mai ușor de făcut corect.
Când ar trebui versionat un API?
Versionați un API doar când o schimbare ar rupe un apelant corect. Schimbările aditive, câmpuri noi, endpoint-uri noi, parametri opționali noi, nu au nevoie de versiune; apelanții scriși pentru contractul vechi continuă să funcționeze, iar noua capacitate e pur și simplu acolo. O schimbare care rupe compatibilitatea are nevoie de una, pentru că alternativa e ca un apelant să afle dintr-o eroare. Versionarea fiecărei lansări, inclusiv cele aditive, îi învață pe apelanți că versiunile sunt zgomot, și încetează să citească notificările care contează.
Testul practic e cel din articolul despre schimbările care rup compatibilitatea: dacă un apelant care s-a bazat doar pe comportamentul documentat trebuie să schimbe ceva ca să continue să funcționeze, schimbarea are nevoie de o versiune. Dacă nu, lansați-o sub versiunea curentă și scrieți o intrare de changelog.
Ce schemă de versionare API ar trebui folosită?
Folosiți schema pe care apelanții voștri o pot vedea și seta cel mai ușor, ceea ce pentru majoritatea API-urilor publice e o versiune în calea URL-ului sau un header de versiune datat. Cele patru scheme comune diferă mai puțin în capacitate decât în ce cer de la apelant, și asta e baza corectă pentru a alege.
| Schemă | Exemplu | Ce trebuie să facă apelantul | Cine o folosește |
|---|---|---|---|
| Cale URL | /v2/invoices | Să schimbe URL-ul la migrare | Majoritatea API-urilor REST publice |
| Header de versiune | X-GitHub-Api-Version: 2022-11-28 | Să trimită un header, sau să accepte implicitul | GitHub |
| Versiune de cont datată | Stripe-Version: 2026-08-26 | Să fixeze o dată per cerere sau per cont | Stripe |
| Parametru de query | /invoices?version=2 | Să adauge un parametru | API-uri mai vechi; rar ales acum |
| Tip de media | Accept: application/vnd.example.v2+json | Să negocieze tipuri de conținut | Puriști; puțini apelanți se descurcă |
Calea URL e cea mai vizibilă și cea mai puțin flexibilă. Fiecare apelant poate vedea în ce versiune e citind o linie de log, iar un salt de versiune e un caută-și-înlocuiește. Costul: întreaga suprafață se mișcă deodată, nu puteți schimba contractul unui singur endpoint fără să bateți o versiune nouă pentru toate, deci versiunile de cale tind să fie rare și mari.
Header-ul de versiune menține URL-urile stabile și lasă serverul să aleagă un implicit pentru
apelanții care nu trimit nimic, așa cum funcționează
versionarea API REST a GitHub:
o versiune numită după dată în X-GitHub-Api-Version, cu cea mai veche versiune suportată ca
implicit ca apelanții nefixați să nu se rupă. Costul: versiunea e invizibilă într-un URL și ușor
de uitat într-un client nou.
Versiunea de cont datată e schema de header plus o adăugire: versiunea e stocată contra
contului, deci fiecare cerere o primește fără să trimită nimic.
Versionarea API a Stripe fixează fiecare cont la
versiunea cu care a fost creat și lasă o cerere să suprascrie asta cu Stripe-Version. E schema
cea mai prietenoasă pentru apelant și cea mai multă muncă de operat, pentru că serverul trebuie
să traducă între fiecare versiune suportată și cea curentă.
Parametrul de query și tipul de media funcționează ambele și eșuează ambele testul de vizibilitate în moduri diferite: un parametru de query se pierde ușor la construirea unui URL, iar o versiune de tip de media e invizibilă pentru aproape orice unealtă cu care ar depana un apelant. Schema datată a Stripe e cel mai cunoscut exemplu al abordării cu dată, iar cum versionează Stripe API-ul o parcurge pas cu pas.
Cum se face versionarea API în practică?
În practică o versiune e un set numit de comportamente, iar serverul mapează fiecare cerere la unul dintre ele. Pașii sunt aceiași indiferent ce schemă poartă numele.
- Numiți versiunile după dată sau număr întreg, nu versiune semantică. Un API web nu e un
pachet. Apelanții nu pot fixa o versiune minor a unui URL, deci
v2sau2026-08-26spune tot ce are nevoie un apelant, iar versionarea semantică sugerează o promisiune de compatibilitate pe care schema n-o poate livra. - Țineți versiunea în afara căilor de cod cărora nu le pasă. O versiune ar trebui să selecteze un strat de traducere la margine, nu să ramifice logica de business. Două copii complete ale bazei de cod e cum o versiune ajunge neîntreținută.
- Dați fiecărei versiuni un implicit și un document. Apelanții care nu trimit versiune primesc cea mai veche suportată, niciodată cea mai nouă, ca un client nefixat să nu se rupă în ziua lansării. Fiecare versiune are o pagină care spune ce s-a schimbat față de cea anterioară.
- Setați o fereastră de suport și publicați-o. Ghidul Google de versionare, AIP-185, cere o perioadă de tranziție rezonabilă și bine comunicată și recomandă 180 de zile chiar și pentru funcționalitățile beta. Alegeți o fereastră, scrieți-o, și aplicați-o fără renegociere per versiune.
- Pensionați versiunile așa cum pensionați endpoint-uri. O versiune trecută de fereastra ei
primește același tratament ca orice API depreciat: un anunț, un
header
Sunset(RFC 8594) în fiecare răspuns, o reamintire la jumătatea drumului către apelanții rămași, și o dată de eliminare care se respectă.
Ce sunt v1 și v2 într-un API REST?
v1 și v2 sunt nume pentru două contracte pe care același server le suportă simultan. Un v2
există pentru că ceva în v1 nu putea fi schimbat fără a rupe apelanții săi, deci schimbarea a
mers într-un contract nou, iar cel vechi a continuat să funcționeze. Numerele nu sugerează că
v2 e complet sau că v1 e mort; ambele sunt adevărate doar dacă documentația o spune. Un v3
care apare în fiecare trimestru e un semn că se versionează schimbări aditive, sau că
contractul n-a fost niciodată proiectat să absoarbă schimbare. gRPC
rezolvă aceeași problemă diferit: schimbări de API gRPC și Protobuf
acoperă versionarea prin numele pachetului dintr-un fișier .proto în loc de o cale URL, și un
format pe wire unde redenumirea unui câmp e gratis dar renumerotarea lui e o schimbare care rupe
compatibilitatea pe care niciun apelant REST n-ar recunoaște-o ca riscantă.
Ce ar trebui să anunțe o schimbare de versiune?
O schimbare de versiune ar trebui să anunțe ce se rupe, pe cine afectează, cum să migreze, și cât timp continuă să funcționeze versiunea anterioară. Intrarea are aceeași formă ca orice altă intrare de schimbare care rupe compatibilitatea, plus o linie care declară fereastra de suport. Iată una pentru un API versionat prin header:
Versiunea API 2026-11-01 e disponibilă. Versiunea 2025-06-15 e suportată până pe 1 noiembrie 2027. Nou în 2026-11-01:
GET /invoicesreturneazăamountîn cele mai mici unități ca un număr întreg în loc de string zecimal, iar câmpul depreciatcustomer_namee eliminat în favoarea obiectuluicustomer. Afectează apelanții pe 2025-06-15 care analizeazăamountca string, ceea ce e implicit pentru clienții nefixați creați înainte de iunie 2025. Migrare: analizațiamountca număr întreg și citiți numele dincustomer.name. FixațiX-Api-Version: 2026-11-01când sunteți gata. Nimic nu se schimbă pentru apelanții care nu fixează versiunea.
Ultima propoziție e cea care le lasă pe majoritatea cititoarelor să se oprească din citit, și aparține fiecărui anunț de versiune. Pagina exemple de changelog include intrări de la API-uri care versionează astfel, iar diferența dintre cele bune și restul stă majoritar în acea ultimă propoziție.
Cine e anunțat când o versiune se schimbă?
Toată lumea de pe versiunea veche, individual, și changelog-ul pentru toți ceilalți. O schimbare de versiune e singurul caz în care “am postat ceva despre asta” garantat ratează exact apelanții care contează: cei care au fixat o versiune acum doi ani și n-au mai citit o notă de lansare de atunci. Datele de utilizare răspund cine sunt ei; notificarea trebuie să-i ajungă unde e codul lor, în header-ele de răspuns și într-un mesaj către proprietara contului.
În bucla pe care o rulăm, intrarea care anunță o versiune e redactată din pull request-ul care o lansează, revizuită de o persoană, și publicată pe flux și widget, unde un client versionat o poate citi ca JSON. Oricine al cărui feedback din widget a cerut schimbarea, sau a raportat eroarea pe care o rezolvă, și a devenit un issue GitHub pe care pull request-ul îl închide, e anunțat pe acel issue de îndată ce intrarea intră în direct. Mecanismul e același ca pentru orice intrare; un salt de versiune e doar intrarea cu cea mai mare miză.
FAQ
Ar trebui fiecare schimbare de API să primească o versiune nouă? Nu. Doar schimbările care rup compatibilitatea. Schimbările aditive sunt lansate sub versiunea curentă cu o intrare de changelog. Versionarea schimbărilor aditive antrenează apelanții să ignore versiunile.
E versionarea prin URL mai bună decât cea prin header? Versionarea prin URL e mai ușor de văzut pentru apelanți și mai greu pentru voi să o evoluați treptat; versionarea prin header e invers. Pentru un API public cu mulți clienți mici, versionarea prin URL eșuează mai puțin. Pentru un API mare cu strat de traducere, versiunea datată prin header scalează mai bine.
Câte versiuni ar trebui suportate simultan? Cât mai puține permite fereastra voastră de suport, și niciodată un număr nelimitat. Două sau trei versiuni concurente e normal; mai mult de atât înseamnă de obicei că versiunile nu sunt pensionate.
Ce ar trebui să primească cererile fără versiune? Cea mai veche versiune suportată, ca clienții existenți nefixați să continue să funcționeze, cu un header de răspuns care le spune ce versiune au primit.
Afirmațiile tehnice din acest articol nu au fost verificate independent. Dacă ceva nu e corect, spune-ne și vom corecta.