Kako se izrađuje REST API

Ako niste dobro upoznati s API-jem, možda se pitate ... zašto tolika frka oko verziranja API-ja?

Ako su vas izgorjele promjene API-ja, vjerojatno se vi nervirate. Ako ste održavatelj API-ja, možda se gnjavite i oko pokušaja postavljanja izazovnih pitanja poput ovih:

# Is this version 2 of just products or of the entire API? /v2/products # What catalyzed the change between v1 and v2? How are they different? /v1/products /v2/products

Na ova pitanja oko izrade verzija nije lako odgovoriti. Nije uvijek jasno na što se v1ili na što v2misli. I ne bismo trebali samo napraviti drugu verziju krajnje točke kad se čini da prva više nije dovoljna.

Postoje jasni razlozi zašto vaš API mora imati verzije verzija, a postoje jasne strategije kako učinkovito kretati se promjenama API-ja.

Međutim, otkrio sam da većina programera - uključujući i mene, dok nisam naučio neke lekcije na teži način - nisu svjesni ovih razloga i strategija.

Ovaj članak pokušava istaknuti one razloge za izradu verzija i strategije za njegovo postizanje. Pretpostavit ćemo REST API kontekst, jer je to standard za mnoge API-je, i usredotočiti se na aspekt verziranja .

Što je inačica verzija?

Trebali bismo započeti s postavljanjem razine o tome što se podrazumijeva pod pojmom "izrada verzija API-ja". Evo naše radne definicije:

Izrada verzija API-ja praksa je transparentnog upravljanja promjenama vašeg API-ja.

Izrada verzija je učinkovita komunikacija oko promjena vašeg API-ja, tako da potrošači znaju što mogu očekivati ​​od toga. Dostavljate podatke javnosti na neki način i trebate komunicirati kada promijenite način na koji se podaci dostavljaju.

Ono na što se ovo svodi, u velikoj mjeri, jest upravljanje ugovorima o podacima i razbijanje promjena. Prvi je primarni gradivni element vašeg API-ja, a drugi otkriva zašto je potrebno izrađivanje verzija.

Ugovori o podacima

API je sučelje za programiranje aplikacija , a sučelje je zajednička granica za razmjenu informacija. Ugovor o podacima srce je ovog sučelja.

Ugovor o podacima je sporazum o obliku i općenitom sadržaju podataka zahtjeva i / ili odgovora.

Da bismo ilustrirali ugovor o podacima, evo osnovnog JSON-ovog tijela za odgovor:

{ "data": [ { "id": 1, "name": "Product 1" }, { "id": 2, "name": "Product 2" } ] }

To je objekt sa dataimovinom koja je niz (popis) proizvoda, svaki s idte nameimovine. Ali datasvojstvo se moglo podjednako lako nazvati body, a idsvojstvo svakog proizvoda moglo je biti GUID umjesto cijelog broja. Ako se vraćao jedan proizvod, to databi mogao biti objekt umjesto niza.

Ove naizgled suptilne promjene mogle bi dovesti do drugačijeg sporazuma, drugačijeg ugovora, u vezi s "oblikom" podataka. Oblik podataka mogao bi se primijeniti na imena svojstava, vrste podataka ili čak na očekivani format (JSON u odnosu na XML).

Zašto je potrebno postavljanje verzija?

Uz API-je, nešto tako jednostavno kao što je promjena naziva svojstva productIdu productIDmože razbiti stvari za potrošače. Upravo se to dogodilo našem timu prošlog tjedna.

Srećom, imali smo testove kako bismo uhvatili promjene u API ugovoru. Međutim, nisu nam trebali biti potrebni ti testovi, jer su održavači API-ja trebali znati da bi to bila velika promjena.

Kršenje promjena

Ovo je bila presudna promjena dogovorenog ugovora o podacima jer nas je njihova promjena natjerala da promijenimo i svoju prijavu.

Što predstavlja "prijelomnu promjenu" u API završnoj točki? Svaka promjena vašeg API ugovora koja prisiljava potrošača da također izvrši promjenu.

Prijelomne promjene prvenstveno se uklapaju u sljedeće kategorije:

  1. Promjena formata zahtjeva / odgovora (npr. Iz XML u JSON)
  2. Promjena naziva svojstva (npr. Iz nameu productName) ili vrste podataka na svojstvu (npr. Iz cijele u plutajuću)
  3. Dodavanje potrebnog polja na zahtjev (npr. Novo potrebno zaglavlje ili svojstvo u tijelu zahtjeva)
  4. Uklanjanje svojstva iz odgovora (npr. Uklanjanje descriptioniz proizvoda)

API upravljanje promjenama

Nikada nije pametno ili ljubazno prisiljavati potrošače API-ja na promjenu. Ako morate napraviti presudnu promjenu, tome je namijenjeno verziranje, a mi ćemo pokriti najučinkovitije načine verzije vaše aplikacije i krajnjih točaka.

Ali prvo, hajde da ukratko razgovaramo o tome kako uopće izbjeći kršenje promjena. Ovo bismo mogli nazvati upravljanje promjenama API-ja.

Učinkovito upravljanje promjenama u kontekstu API-ja sažeto je prema sljedećim načelima:

  • Nastavite s podrškom za postojeća svojstva / krajnje točke
  • Dodajte nova svojstva / krajnje točke umjesto mijenjanja postojećih
  • Zamišljeno zalazak zastarjelih svojstava / krajnjih točaka

Evo primjera koji demonstrira sva tri navedena načela u kontekstu odgovora na zahtjev za korisničkim podacima:

{ "data": { "id": 1, "name": "Carlos Ray Norris", // original property "firstName": "Carlos", // new property "lastName": "Norris", // new property "alias": "Chuck", // obsolete property "aliases": ["Chuck", "Walker"] // new property }, "meta": { "fieldNotes": [ { "field": "alias", "note": "Sunsetting on [future date]. Please use aliases." } ] } }

U ovom primjeru, namebilo je izvorno svojstvo. U firstNamei lastNamepolja se provode kako bi osigurao precizniji opciju, u slučaju da potrošač želi prikazati „gospodina Norris” s nekim string interpolacije, ali bez analizirati namepolje. Međutim, nameimovina će biti podržana u kontinuitetu.

alias, s druge strane, zastarjet će u korist aliasesniza - jer Chuck ima toliko pseudonima - a u odgovoru postoji napomena koja ukazuje na vremenski okvir zalaska sunca.

Kako verzirate API?

Ovi će principi trebati dug put u navigaciji promjenama vašeg API-ja bez potrebe za uvođenjem nove verzije. Međutim, ponekad je to moguće izbjeći, a ako trebate potpuno novi ugovor o podacima, trebat će vam nova verzija vaše krajnje točke. Dakle, morat ćete to na neki način priopćiti javnosti.

Kao stranu, imajte na umu da ne govorimo o verziji temeljne baze koda. Dakle, ako za svoju aplikaciju koristite semantičko upravljanje verzijama koje također podržava javni API, vjerojatno ćete htjeti razdvojiti te sustave za izradu verzija.

Kako stvoriti novu verziju svog API-ja? Koje su različite metode za to? Morat ćete odrediti koju vrstu strategije izrade verzija želite općenito, a dok razvijate i održavate svoj API, morat ćete odrediti opseg svake promjene verzije.

Opseg

Prvo se pozabavimo opsegom. Kao što smo prethodno istražili, ponekad će ugovori o podacima biti ugroženi neprimjerenom promjenom, a to znači da ćemo morati pružiti novu verziju ugovora o podacima. To bi moglo značiti novu verziju krajnje točke ili može značiti promjenu u globalnijem opsegu primjene.

Možemo razmišljati o razinama promjene opsega unutar analogije stabla:

  • Leaf - Promjena izolirane krajnje točke bez veze s drugim krajnjim točkama
  • Grana - Promjena grupe krajnjih točaka ili resursa kojem se pristupa kroz nekoliko krajnjih točaka
  • Trunk - Promjena na razini aplikacije koja jamči promjenu verzije na većini ili svim krajnjim točkama
  • Root - promjena koja utječe na pristup svim API resursima svih verzija

Kao što vidite, promjenom od lista do korijena, promjene postaju sve snažnije i globalnije.

List opseg često mogu biti obrađene kroz učinkovito upravljanje API promjena. Ako nije, jednostavno stvorite novu krajnju točku s novim ugovorom o podacima o resursima.

Grana je malo trickier, ovisno o samo koliko konačna utječe promjena ugovora podaci o resursima u pitanju. Ako su promjene relativno ograničene na jasnu skupinu povezanih krajnjih točaka, potencijalno biste se mogli kretati ovime uvođenjem novog naziva resursa i ažuriranjem dokumenata u skladu s tim.

# variants, which has a breaking change, is accessed on multiple routes /variants /products/:id/variants # we introduce product-variants instead /product-variants /products/:id/product-variants

Prtljažnik se odnosi na promjene na razini aplikacija koje su često rezultat promjena u jednoj od sljedećih kategorija:

  • Format (npr. Iz XML u JSON)
  • Specifikacija (npr. Od vlastite do JSON API ili Open API)
  • Potrebna zaglavlja (npr. Za provjeru autentičnosti / autorizaciju)

To će zahtijevati promjenu vaše ukupne verzije API-ja, pa biste trebali pažljivo planirati i dobro izvršiti prijelaz.

A root change will force you to go one step further in ensuring that all consumers of all versions of your API are aware of the change.

Types of API Versioning

As we turn to different types of API versioning, we'll want to use these insights into varying scopes of API changes to evaluate the types. Each approach has its own set of strengths and weaknesses in addressing changes based on their scope.

There are several methods for managing the version of your API. URI path versioning is the most common.

URI Path

//www.example.com/api/v1/products //api.example.com/v1/products

This strategy involves putting the version number in the path of the URI, and is often done with the prefix "v". More often than not, API designers use it to refer to their application version (i.e. "trunk") rather than the endpoint version (i.e. "leaf" or "branch"), but that's not always a safe assumption.

URI path versioning implies orchestrated releases of application versions that will require one of two approaches: maintaining one version while developing a new one or forcing consumers to wait for new resources until the new version is released. It also means you'd need to carry over any non-changed endpoints from version to version. However, for APIs with relatively low volatility, it's still a decent option.

You would likely not want to relate your version number to that of the endpoint or resource, because it would easily result in something like a v4 of products but a v1 of variants, which would be rather confusing.

Query Params

//www.example.com/api/products?version=1

This type of versioning adds a query param to the request that indicates the version. Very flexible in terms of requesting the version of the resource you'd like at the "leaf" level, but it holds no notion of the overall API's version and lends itself to the same out-of-sync issues mentioned in the above comment on endpoint-level versioning of the URI path.

Header

Accept: version=1.0

The header approach is one that provides more granularity in serving up the requested version of any given resource.

However, it's buried in the request object and isn't as transparent as the URI path option. It's also still hard to tell whether 1.0 refers to the version of the endpoint or the API itself.

Integrating Types

Each of these approaches seem to have the weakness of either favoring a "leaf" or "trunk" scope, but not supporting both.

If you need to maintain the overall API version and also provide support for multiple versions of resources, consider a blend of the URI Path and Query Params types, or a more advanced Header approach.

# URI path and query params combo //api.example.com/v1/products?version=1 //api.example.com/v1/products?version=2 # Extended headers, for //api.example.com/products Accept: api-version=1; resource-version=1 Accept: api-version=1; resource-version=2

Conclusion

We've covered a lot of ground here, so let's recap:

  • API versioning is the practice of transparently managing changes to your API.
  • Managing an API boils down to defining and evolving data contracts and dealing with breaking changes.
  • The most effective way to evolve your API without breaking changes is to follow effective API change management principles.
  • For most APIs, versioning in the URI path is the most straightforward solution.
  • For more complex or volatile APIs, you can manage varying scopes of changes by employing an integration of URI path and query params approaches.

Although these principles should provide clear direction in how to effectively manage change to your APIs, evolving an API is potentially more of an art than a science. It requires thought and foresight to create and maintain a reliable API.