Cum se depreciază un API fără a pierde dezvoltatorii
6 min de citit
A deprecia un API înseamnă să anunțați că ceva încă funcționează astăzi și va înceta să funcționeze la o dată declarată, apoi să respectați ambele jumătăți ale acelei promisiuni. Majoritatea deprecierilor eșuează la a doua jumătate: data alunecă în tăcere, sau sosește, iar apelanții care n-au văzut niciodată notificarea află dintr-o eroare. O depreciere e terminată când fiecare apelant afectat fie a migrat, fie a fost anunțat, individual, că nu a făcut-o.
Ce e deprecierea unui API?
Deprecierea e perioada dintre a anunța că un endpoint, câmp sau versiune va dispărea și eliminarea lui efectivă. În acea perioadă comportamentul vechi continuă să funcționeze, documentația spune că pleacă, iar fiecare răspuns poartă un avertisment lizibil de mașină. Eliminarea e evenimentul separat, ulterior, adesea numit sunset. Cele două se confundă, iar acea confuzie e locul unde se produce dauna: “deprecated” începe să însemne “poate a dispărut deja”, iar apelanții încetează să mai aibă încredere în niciunul dintre cuvinte.
| Termen | Semnificație | Pe ce se pot baza apelanții |
|---|---|---|
| Deprecated | Anunțat ca dispărând, încă funcționează | Comportament complet până la data sunset |
| Sunset | Data la care încetează să funcționeze | Nimic după această dată |
| Retired / eliminat | Dispărut; cererile eșuează | O eroare, ideal una care numește înlocuitorul |
| Legacy | Nedefinit. Evitați cuvântul | Nimic, ceea ce e problema |
Cât ar trebui să dureze o perioadă de depreciere?
Suficient de lungă ca un apelant să afle și să facă munca, măsurată din momentul în care notificarea l-a ajuns, nu din momentul în care ați scris-o. Nouăzeci de zile e pragul comun pentru un API web public. Douăsprezece luni e normal pentru orice e încorporat în software pe care utilizatorii finali îl instalează, pentru că corecția trebuie de asemenea să treacă prin procesul lor de lansare. Ghidul Google de versionare, AIP-185, cere o perioadă de tranziție rezonabilă și recomandă 180 de zile chiar și înainte de eliminarea funcționalităților beta, iar Kubernetes își documentează politica de depreciere în număr de lansări în loc de luni, ceea ce e unitatea corectă când apelanții voștri actualizează după versiune.
Alegeți o perioadă, scrieți-o ca politică, și opriți-vă din a o decide per schimbare. O politică publicată transformă fiecare depreciere dintr-o negociere într-o aplicare a unei reguli.
Scrierea politicii de depreciere acoperă începutul ferestrei; retragerea unei versiuni de API acoperă notificarea separată necesară la final, când perioada chiar se termină și versiunea încetează să funcționeze.
Programul deprecierii
Patru date, anunțate împreună în prima zi. Fiecare e o intrare de changelog separată la sosire, deci povestea e spusă de patru ori oricui citește doar changelog-ul.
- Anunțați. Intrarea spune ce e depreciat, de ce, ce-l înlocuiește, și data sunset. Documentația lucrului vechi câștigă un banner care leagă la migrare. Răspunsurile câștigă header-ele descrise mai jos.
- Reamintiți, la jumătatea drumului. O a doua intrare, și un mesaj direct fiecărui apelant care încă folosește comportamentul vechi. Ăsta e pasul care are nevoie de date de utilizare: dacă nu puteți lista cine încă apelează endpoint-ul depreciat, nu puteți face asta, și merită reparat înainte de următoarea depreciere.
- Brownout, cu puțin timp înainte de dată. Returnați erori pentru comportamentul vechi printr-o fereastră scurtă, o oră sau o zi, apoi restaurați-l. Apelanții care au ratat fiecare notificare află acum, cât mai e timp. GitHub a folosit brownout-uri programate înainte de a pensiona autentificarea prin parolă pentru API, și e cel mai eficient pas individual din această listă.
- Sunset. Eliminați-l. Eroarea care-l înlocuiește numește înlocuitorul și leagă la ghidul de migrare. Păstrați eroarea la locul ei mult timp; un 404 nu-i spune nimic unui apelant.
Ce ar trebui să spună o notificare de depreciere?
O notificare de depreciere spune ce dispare, când se oprește, ce să folosiți în loc, și pe cine afectează. Iată forma, completată:
GET /v1/reports/dailye depreciat și încetează să funcționeze pe 1 martie 2027. E înlocuit deGET /v2/reports?granularity=day, care returnează aceleași date cu o schemă stabilă și paginare. Afectează cele 214 integrări care au apelat endpoint-ul v1 în ultimele 30 de zile; dacă a voastră e una dintre ele, veți primi și această notificare prin e-mail. Ghid de migrare: [link]. Nimic nu se schimbă până pe 1 martie 2027. De la acea dată endpoint-ul v1 returnează410 Gonecu un link către această intrare.
Fiecare propoziție poartă ceva de care are nevoie cititoarea. Numărul integrărilor afectate îi spune fiecărei cititoare dacă ar trebui să continue să citească. “Nimic nu se schimbă până” e propoziția care le lasă pe cele neafectate să închidă tab-ul. Pagina exemple de changelog adună intrări de la echipe care scriu această formă consecvent, și merită citite trei înainte de a scrie prima proprie.
Ce header-e ar trebui să trimită un endpoint depreciat?
Trimiteți Deprecation, Sunset și un Link către succesor, în fiecare răspuns de la
endpoint-ul depreciat, din ziua anunțului. Header-ul Deprecation
poartă data la care deprecierea a intrat în vigoare; header-ul Sunset
poartă data la care endpoint-ul încetează să răspundă; Link: <url>; rel="successor-version"
indică ce să folosiți în loc.
HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: <https://api.example.com/v2/reports>; rel="successor-version"
Link: <https://example.com/changelog/daily-reports>; rel="deprecation"
Majoritatea apelanților nu vor citi niciodată header-ele înseși. Valoarea lor e că o pot citi clientul HTTP, gateway-ul sau monitorizarea unui apelant, ceea ce transformă deprecierea voastră într-o alertă de partea lor în loc de o pagină de partea voastră. SDK-urile pe care le livrați ar trebui să înregistreze un avertisment când văd unul.
Cine a fost anunțat, și de unde știți?
Ăsta e pasul care decide dacă sunset-ul e liniștit sau devine un incident de suport, și e cel mai greu de făcut doar cu un changelog. O intrare de changelog anunță pe oricine citește changelog-ul. O depreciere trebuie să ajungă la oamenii specifici al căror cod va eșua, iar modul obișnuit de a-i găsi sunt aceleași date de utilizare de care are nevoie reamintirea de la jumătatea drumului: cheile API, aplicațiile sau conturile care au apelat comportamentul depreciat recent.
Bucla pe care o rulăm: intrarea e redactată din pull request-ul care adaugă deprecierea, o persoană revizuiește formularea și data, iar odată publicată intrarea în sine e notificarea. Oricine al cărui feedback din widget despre problemă, sau cerere pentru înlocuitor, a devenit un issue GitHub pe care pull request-ul îl închide primește un comentariu pe acel issue spunând că a fost lansat, cu un link către intrare. Fluxul și widget-ul servesc aceeași intrare tuturor celorlalți, alături de fiecare altă intrare din changelog-ul de API. Ce nu facem e să lăsăm deprecierea să devină “lansată” înainte ca o persoană s-o fi publicat; o notificare cu data greșită e mai rea decât nicio notificare.
Indiferent de uneltele voastre, întrebarea la care trebuie să puteți răspunde în ziua sunset e: care apelanți încă foloseau asta săptămâna trecută, și cărora dintre ei le-am spus direct? Dacă răspunsul e “am postat ceva despre asta”, sunset-ul nu e gata.
Care e diferența dintre deprecierea și versionarea?
Versionarea e modul în care păstrați comportamentul vechi disponibil în timp ce cel nou există; deprecierea e modul în care pensionați pe cel vechi. O versiune nouă de API fără o politică de depreciere pentru cea anterioară e un angajament de a rula ambele pentru totdeauna. O depreciere fără versionare e o schimbare care rupe compatibilitatea cu întârziere. Aveți nevoie de ambele, iar versiunea e jumătatea mai ușoară. GraphQL e excepția care merită numită: de obicei nu există deloc un număr de versiune de incrementat, iar deprecierea schemei GraphQL acoperă cum o singură schemă comună pensionează un câmp cu o directivă în schimb.
FAQ
Ar trebui un endpoint depreciat să continue să funcționeze exact ca înainte? Da, până la data sunset. Singurele schimbări permise sunt header-ele adăugate și, aproape de final, un brownout programat pe care l-ați anunțat în avans.
Ce cod de status ar trebui să returneze un endpoint pensionat?
410 Gone, cu un corp și un header Link care indică înlocuitorul și intrarea de changelog.
404 spune că URL-ul n-a existat niciodată, ceea ce e fals și nefolositor.
Poate fi scurtată o perioadă de depreciere? Doar pentru securitate. Dacă comportamentul vechi e exploatabil, spuneți asta, scurtați perioada, și spuneți-i fiecărui apelant afectat direct în loc să vă bazați pe changelog.
Trebuie să depreciez un câmp, sau doar endpoint-uri întregi? Câmpurile, parametrii, valorile enum, valorile implicite și header-ele au toate nevoie de același tratament, pentru că fiecare poate rupe un apelant corect. Un câmp eliminat e cea mai comună depreciere și cea mai des omisă.
Afirmațiile tehnice din acest articol nu au fost verificate independent. Dacă ceva nu e corect, spune-ne și vom corecta.