Versioning af en REST API

1. Problemet

Udvikling af en REST API er et vanskeligt problem - som mange muligheder er tilgængelige for. Denne artikel diskuterer nogle af disse muligheder.

2. Hvad er der i kontrakten?

Før noget andet er vi nødt til at besvare et simpelt spørgsmål: Hvad er kontrakten mellem API og Klient?

2.1. URI er en del af kontrakten?

Lad os først overveje URI-strukturen i REST API - er det en del af kontrakten? Skal klienter bogmærke, hardcode og generelt stole på URI'er i API'en?

Hvis dette er tilfældet, ville interaktionen mellem klienten og REST-tjenesten ikke længere være drevet af selve tjenesten, men af ​​hvad Roy Fielding kalder uden for bandet Information:

En REST API skal indtastes uden forudgående viden ud over det oprindelige URI (bogmærke) og sæt standardiserede medietyper, der passer til det tilsigtede publikum ... Fejl her indebærer, at information uden for båndet driver interaktion i stedet for hypertekst.

Så klart URI'er er ikke en del af kontrakten! Klienten skal kun kende en enkelt URI - adgangspunktet til API'en. Alle andre URI'er skal opdages, mens de bruger API.

2.2. Medietyper del af kontrakten?

Hvad med de mediatypeoplysninger, der bruges til repræsentation af ressourcer - er disse en del af kontrakten mellem klienten og tjenesten?

For at kunne bruge API'et med succes, skal klienten have forudgående kendskab til disse medietyper. Faktisk repræsenterer definitionen af ​​disse medietyper hele kontrakten.

Derfor er det her, hvor REST-tjenesten skal fokusere mest:

En REST API skal bruge næsten al sin beskrivende indsats på at definere den / de medietyper, der bruges til at repræsentere ressourcer og køre applikationstilstand, eller til at definere udvidede relationsnavne og / eller hypertekst-aktiveret markering for eksisterende standardmedietyper.

Definitioner af medietyper er en del af kontrakten og skal være forudgående viden for den klient, der bruger API'en. Det er her, standardisering kommer ind.

Vi har nu en god idé om, hvad kontrakten er, lad os gå videre til, hvordan vi rent faktisk tackler versioneringsproblemet.

3. Indstillinger på højt niveau

Lad os nu diskutere fremgangsmåderne på højt niveau til versionering af REST API:

  • URI-versionering - versioner URI-rummet ved hjælp af versionsindikatorer
  • Medietype versionering - version af repræsentationen af ​​ressourcen

Når vi introducerer versionen i URI-rummet, betragtes repræsentationerne af ressourcer som uforanderlige. Så når ændringer skal introduceres i API'en, skal der oprettes et nyt URI-rum.

Lad os f.eks. Sige, at en API offentliggør følgende ressourcer - brugere og privilegier:

// vært / v1 / brugere // vært / v1 / privilegier

Lad os nu overveje, at en brudende ændring i brugere API kræver introduktion af en anden version:

// vært / v2 / brugere // vært / v2 / privilegier

Når vi versionerer medietypen og udvider sproget, gennemgår vi indholdsforhandling baseret på denne overskrift. REST API vil bruge brugerdefinerede leverandør MIME-medietyper i stedet for generiske medietyper som f.eks ansøgning / json. Vi vil versionere disse medietyper i stedet for URI'erne.

For eksempel:

===> GET / brugere / 3 HTTP / 1.1 Accepter: applikation / vnd.myname.v1 + json <=== HTTP / 1.1 200 OK Indholdstype: applikation / vnd.myname.v1 + json {"bruger": {"name": "John Smith"}}

Vi kan tjekke denne 'Custom Media Typer for Rest APIs' -artikel for yderligere information og eksempler vedrørende dette emne.

Hvad der er vigtigt at forstå her er det klienten antager ikke antagelser om reaktionens struktur ud over hvad der er defineret i medietypen.

Derfor er generiske medietyper ikke ideelle. Disse giver ikke nok semantisk information og tvinge klienten til at bruge kræve yderligere tip til at behandle den faktiske repræsentation af ressourcen.

En undtagelse fra dette er at bruge en anden måde til entydigt at identificere semantikken i indholdet - såsom et XML-skema.

4. Fordele og ulemper

Nu hvor vi har et klart koncept for, hvad der er en del af kontrakten mellem klienten og tjenesten, samt et overblik på højt niveau af mulighederne for version af API'et, lad os diskutere fordele og ulemper ved hver tilgang.

Først, introduktion af versionsidentifikatorer i URI fører til et meget stort URI-fodaftryk. Dette skyldes det faktum, at enhver brudende ændring i nogen af ​​de offentliggjorte API'er introducerer et helt nyt repræsentationstræ for hele API'en. Over tid bliver dette en byrde at vedligeholde såvel som et problem for klienten - som nu har flere muligheder at vælge imellem.

Versionsidentifikatorer i URI ER også meget ufleksible. Der er ingen måde blot at udvikle API'en til en enkelt ressource eller en lille delmængde af den samlede API.

Som vi nævnte før, er dette en alt eller intet tilgang. Hvis en del af API'en flytter til den nye version, skal hele API'en gå videre med den. Dette gør også opgradering af klienter fra v1 til v2 til en større opgave - hvilket fører til langsommere opgraderinger og meget længere solnedgangsperioder for de gamle versioner.

HTTP-caching er også et stort problem, når det kommer til versionering.

Fra perspektivet af proxy-cacher i midten har hver tilgang fordele og ulemper. Hvis URI er versioneret, skal cachen beholde flere kopier af hver ressource - en til hver version af API'et. Dette lægger en belastning på cachen og mindsker cache-hitfrekvensen, da forskellige klienter bruger forskellige versioner.

Nogle cache-ugyldighedsmekanismer fungerer også ikke længere. Hvis medietypen er den, der er versioneret, skal både klienten og tjenesten understøtte Vary HTTP-overskriften for at indikere, at der er flere versioner, der cachelagres.

Fra perspektiv på klientcaching løsningen, der versioner medietypen, involverer dog lidt mere arbejde end den, hvor URI'er indeholder version-id'en. Dette skyldes, at det simpelthen er nemmere at cache noget, når nøglen er en URL end en medietype.

Lad os afslutte dette afsnit med at definere nogle mål (lige ud af API Evolution):

  • holde kompatible ændringer ude af navne
  • undgå nye større versioner
  • foretager ændringer bagudkompatible
  • tænk på fremad-kompatibilitet

5. Mulige ændringer af API

Lad os derefter overveje, hvilke typer ændringer til REST API - disse introduceres her:

  • repræsentationsformatændringer
  • ressourceændringer

5.1. Tilføjelse til repræsentationen af ​​en ressource

Formattedokumentationen for medietypen skal designes med tanke på fremadrettet kompatibilitet. Specifikt skal en klient ignorere information, som den ikke forstår (hvilken JSON gør bedre end XML).

Nu, tilføjelse af oplysninger i repræsentationen af ​​en ressource bryder ikke eksisterende klienter, hvis disse er korrekt implementeret.

For at fortsætte vores tidligere eksempel tilføje beløb i repræsentationen af bruger vil ikke være en brudende ændring:

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

5.2. Fjernelse eller ændring af en eksisterende repræsentation

Fjernelse, omdøbning eller generelt omstrukturering af information i designet af eksisterende repræsentationer er en banebrydende ændring for klienter. Dette skyldes, at de allerede forstår og stoler på det gamle format.

Det er her, indholdsforhandling kommer ind. For sådanne ændringer, vi kan tilføje en ny leverandør MIME-medietype.

Lad os fortsætte med det foregående eksempel. Sig, at vi vil bryde navn af bruger ind i fornavn og efternavn:

===> GET / brugere / 3 HTTP / 1.1 Accepter: applikation / vnd.myname.v2 + json <=== HTTP / 1.1 200 OK Indholdstype: applikation / vnd.myname.v2 + json {"bruger": {"firstname": "John", "lastname": "Smith", "amount": "300"}}

Som sådan repræsenterer dette en inkompatibel ændring for klienten - som bliver nødt til at anmode om den nye repræsentation og forstå den nye semantik. URI-rummet forbliver dog stabilt og påvirkes ikke.

5.3. Store semantiske ændringer

Dette er ændringer i betydningen af ​​ressourcerne, forholdet mellem dem eller hvad kortet skal være i backend. Denne form for ændringer kan kræve en ny medietype, eller de kan kræve offentliggørelse af en ny, søskende ressource ved siden af ​​den gamle og brug af link til at pege på den.

Mens dette lyder som at bruge version-identifikatorer i URI igen, er den vigtige forskel, at den nye ressource offentliggøres uafhængigt af andre ressourcer i API'en og forkaster ikke hele API'en ved roden.

REST API skal overholde HATEOAS-begrænsningen. Ifølge dette skal de fleste URI'er OPDAGES af klienter, ikke hardkodede. Ændring af en sådan URI bør ikke betragtes som en uforenelig ændring. Den nye URI kan erstatte den gamle, og klienter kan genopdage URI og stadig fungere.

Det er dog værd at bemærke, at mens brug af version-identifikatorer i URI er problematisk af alle disse grunde, det er ikke un-RESTful på nogen måde.

6. Konklusion

Denne artikel forsøgte at give et overblik over det meget forskelligartede og vanskelige problem med udvikler en REST-tjeneste. Vi diskuterede de to fælles løsninger, fordele og ulemper ved hver enkelt og måder at begrunde disse tilgange i forbindelse med REST.

Artiklen afsluttes med at argumentere for den anden løsning - versionering af medietyperne mens man undersøger de mulige ændringer i en RESTful API.

Den fulde implementering af denne vejledning kan findes i GitHub-projektet.

7. Yderligere læsning

Normalt er disse læsningsressourcer knyttet sammen i hele artiklen, men i dette tilfælde er der simpelthen for mange gode:

    • REST API'er skal være hypertekstdrevet
    • API Evolution
    • Link til en HTTP API
    • Kompatibilitetsstrategier