Versiebeheer van een REST API

1. Het probleem

Een REST API ontwikkelen is een moeilijk probleem waarvoor veel opties beschikbaar zijn. In dit artikel worden enkele van deze opties besproken.

2. Wat staat er in het contract?

Voor alles moeten we een simpele vraag beantwoorden: Wat is het contract tussen de API en het Cliënt?

2.1. URI's maken deel uit van het contract?

Laten we eerst eens kijken de URI-structuur van de REST API - maakt dat deel uit van het contract? Moeten klanten bookmarken, hardcoderen en in het algemeen vertrouwen op URI's van de API?

Als dit het geval is, wordt de interactie van de Klant met de REST-service niet langer gestuurd door de service zelf, maar door wat Roy Fielding noemt out-of-band informatie:

Een REST API moet worden ingevoerd zonder voorkennis buiten de initiële URI (bladwijzer) en een reeks gestandaardiseerde mediatypen die geschikt zijn voor het beoogde publiek ... Een mislukking hier impliceert dat out-of-band informatie interactie aanstuurt in plaats van hypertekst.

Zo duidelijk URI's maken geen deel uit van het contract! De client mag slechts één URI kennen - het toegangspunt tot de API. Alle andere URI's moeten worden ontdekt tijdens het gebruik van de API.

2.2. Mediatypen die deel uitmaken van het contract?

Hoe zit het met de mediatype-informatie die wordt gebruikt voor de weergave van bronnen - maken deze deel uit van het contract tussen de klant en de service?

Om de API met succes te kunnen gebruiken, moet de klant voorkennis hebben van deze mediatypen. In feite vertegenwoordigt de definitie van deze mediatypen het hele contract.

Daarom is dit waar de REST-service het meest op moet focussen:

Een REST API zou bijna al zijn beschrijvende inspanning moeten besteden aan het definiëren van het / de mediatype (s) die worden gebruikt voor het weergeven van bronnen en het aansturen van de applicatiestatus, of aan het definiëren van uitgebreide relatienamen en / of op hypertext gebaseerde markeringen voor bestaande standaard mediatypen.

Dus de Mediatype-definities maken deel uit van het contract en moet voorkennis zijn voor de klant die de API gebruikt. Dit is waar standaardisatie om de hoek komt kijken.

We hebben nu een goed idee van wat het contract is, laten we verder gaan met hoe we het versieprobleem daadwerkelijk kunnen aanpakken.

3. Opties op hoog niveau

Laten we nu de benaderingen op hoog niveau bespreken voor versiebeheer van de REST API:

  • URI-versiebeheer - versie de URI-ruimte met behulp van versie-indicatoren
  • Versiebeheer van mediatype - versie de weergave van de bron

Wanneer we de versie in de URI-ruimte introduceren, worden de representaties van bronnen als onveranderlijk beschouwd. Dus als er wijzigingen in de API moeten worden aangebracht, moet er een nieuwe URI-ruimte worden gemaakt.

Stel dat een API de volgende bronnen publiceert: gebruikers en privileges:

// host / v1 / gebruikers // host / v1 / privileges

Laten we nu eens kijken dat een ingrijpende verandering in de gebruikers API vereist de introductie van een tweede versie:

// host / v2 / gebruikers // host / v2 / privileges

Wanneer we het mediatype versienen en de taal uitbreiden, doorlopen we inhoudsonderhandelingen op basis van deze koptekst. De REST API zou gebruik maken van MIME-mediatypen van de leverancier in plaats van generieke mediatypen zoals applicatie / json. We gaan deze mediatypen versieren in plaats van de URI's.

Bijvoorbeeld:

===> GET / users / 3 HTTP / 1.1 Accepteer: application / vnd.myname.v1 + json <=== HTTP / 1.1 200 OK Content-Type: application / vnd.myname.v1 + json {"user": {"name": "John Smith"}}

We kunnen dit artikel ‘Aangepaste mediatypen voor rest-API's’ lezen voor meer informatie en voorbeelden over dit onderwerp.

Wat hier belangrijk is om te begrijpen, is dat de opdrachtgever doet geen aannames over de opbouw van de respons verder dan wat is gedefinieerd in het mediatype.

Dit is de reden waarom generieke mediatypen niet ideaal zijn. Deze geef niet genoeg semantische informatie en de cliënt dwingen om aanvullende hints te gebruiken om de feitelijke representatie van de bron te verwerken.

Een uitzondering hierop is het gebruik van een andere manier om de semantiek van de inhoud uniek te identificeren, zoals een XML-schema.

4. Voordelen en nadelen

Nu we een duidelijk concept hebben van wat deel uitmaakt van het contract tussen de klant en de service, en een overzicht op hoog niveau van de opties om de API te versieren, laten we de voor- en nadelen van elke benadering bespreken.

Eerste, het introduceren van versie-ID's in de URI leidt tot een zeer grote URI-footprint. Dit komt door het feit dat elke ingrijpende wijziging in een van de gepubliceerde API's een geheel nieuwe boom van representaties voor de gehele API zal introduceren. Na verloop van tijd wordt dit zowel een last om te onderhouden als een probleem voor de klant - die nu meer opties heeft om uit te kiezen.

Versie-ID's in de URI ZIJN ook zeer inflexibel. Er is geen manier om eenvoudigweg de API van een enkele resource of een kleine subset van de algehele API te evolueren.

Zoals we eerder vermeldden, is dit een alles of niets-benadering. Als een deel van de API naar de nieuwe versie verhuist, dan moet de hele API meebewegen. Dit maakt het upgraden van clients van v1 naar v2 ook een grote onderneming - wat leidt tot langzamere upgrades en veel langere sunset-periodes voor de oude versies.

HTTP-caching is ook een grote zorg als het gaat om versiebeheer.

Vanuit het perspectief van proxy-caches in het midden heeft elke benadering voor- en nadelen. Als de URI een versie heeft, moet de cache meerdere exemplaren van elke bron bewaren - één voor elke versie van de API. Dit belast de cache en verlaagt de hit-rate van de cache, aangezien verschillende clients verschillende versies zullen gebruiken.

Ook zullen sommige mechanismen voor het ongeldig maken van de cache niet langer werken. Als het mediatype het type is met versiebeheer, dan moeten zowel de client als de service de Vary HTTP-header ondersteunen om aan te geven dat er meerdere versies in de cache worden opgeslagen.

Van de perspectief van client caching De oplossing die versies van het mediatype maakt, brengt echter iets meer werk met zich mee dan degene waarbij URI's de versie-ID bevatten. Dit komt omdat het simpelweg gemakkelijker is om iets in het cachegeheugen te bewaren als de sleutel een URL is dan een mediatype.

Laten we dit gedeelte beëindigen met het definiëren van enkele doelen (rechtstreeks uit API Evolution):

  • houd compatibele wijzigingen uit namen
  • vermijd nieuwe hoofdversies
  • maakt wijzigingen achterwaarts compatibel
  • denk na over voorwaartse compatibiliteit

5. Mogelijke wijzigingen aan de API

Laten we vervolgens eens kijken naar de soorten wijzigingen in de REST API - deze worden hier geïntroduceerd:

  • weergave formaat verandert
  • resource veranderingen

5.1. Toevoegen aan de weergave van een bron

De formaatdocumentatie van het mediatype moet worden ontworpen met het oog op voorwaartse compatibiliteit. In het bijzonder moet een klant informatie negeren die hij niet begrijpt (die JSON beter doet dan XML).

Nu, het toevoegen van informatie in de weergave van een bron zal bestaande klanten niet breken als deze correct zijn geïmplementeerd.

Om door te gaan met ons eerdere voorbeeld, voegt u de extensie bedrag in de weergave van de gebruiker zal geen ingrijpende verandering zijn:

{"user": {"name": "John Smith", "amount": "300"}}

5.2. Een bestaande weergave verwijderen of wijzigen

Het verwijderen, hernoemen of in het algemeen herstructureren van informatie in het ontwerp van bestaande weergaven is een ingrijpende verandering voor klanten. Dit komt omdat ze het oude formaat al begrijpen en erop vertrouwen.

Dit is waar Content Negotiation om de hoek komt kijken. Voor dergelijke wijzigingen, we kunnen een nieuw MIME-mediatype van de leverancier toevoegen.

Laten we doorgaan met het vorige voorbeeld. Stel dat we het naam van de gebruiker in Voornaam en achternaam:

===> GET / users / 3 HTTP / 1.1 Accepteer: application / vnd.myname.v2 + json <=== HTTP / 1.1 200 OK Content-Type: application / vnd.myname.v2 + json {"user": {"firstname": "John", "lastname": "Smith", "amount": "300"}}

Als zodanig vertegenwoordigt dit een onverenigbare wijziging voor de Klant - die de nieuwe Vertegenwoordiging zal moeten aanvragen en de nieuwe semantiek moet begrijpen. De URI-ruimte blijft echter stabiel en wordt niet beïnvloed.

5.3. Grote semantische veranderingen

Dit zijn veranderingen in de betekenis van de bronnen, de relaties daartussen of wat de kaart in de backend is. Dit soort wijzigingen kan een nieuw mediatype vereisen, of het kan nodig zijn om een ​​nieuwe bron op hetzelfde niveau te publiceren naast de oude en gebruik te maken van links om ernaar te verwijzen.

Hoewel dit klinkt als het opnieuw gebruiken van versie-ID's in de URI, is het belangrijke onderscheid dat de nieuwe Resource wordt onafhankelijk van andere bronnen in de API gepubliceerd en zal niet de volledige API naar de root splitsen.

De REST API moet voldoen aan de HATEOAS-beperking. Volgens dit zouden de meeste URI's moeten worden ONTDEKT door klanten, niet hardcoded. Het wijzigen van een dergelijke URI mag niet als een onverenigbare wijziging worden beschouwd. De nieuwe URI kan de oude vervangen en Clients kunnen de URI opnieuw ontdekken en nog steeds functioneren.

Het is echter vermeldenswaard dat, hoewel het gebruik van versie-ID's in de URI om al deze redenen problematisch is, het is niet onrustig hoe dan ook.

6. Conclusie

Dit artikel probeerde een overzicht te geven van het zeer diverse en moeilijke probleem van een REST-service ontwikkelen. We bespraken de twee gemeenschappelijke oplossingen, voor- en nadelen van elk, en manieren om over deze benaderingen te redeneren in de context van REST.

Het artikel besluit door te pleiten voor de tweede oplossing - versiebeheer van de mediatypen terwijl we de mogelijke wijzigingen aan een RESTful API onderzoeken.

De volledige implementatie van deze tutorial is te vinden in het GitHub-project.

7. Verder lezen

Meestal zijn deze leesmiddelen door het hele artikel heen gelinkt, maar in dit geval zijn er gewoon te veel goede:

    • REST API's moeten hypertext-gestuurd zijn
    • API-evolutie
    • Koppelen voor een HTTP-API
    • Compatibiliteitsstrategieën

$config[zx-auto] not found$config[zx-overlay] not found