Eliminer oppsigelser i RAML med ressurstyper og egenskaper

Denne artikkelen er en del av en serie: • Introduksjon til RAML - The RESTful API Modeling Language

• Eliminer oppsigelser i RAML med ressurstyper og trekk (nåværende artikkel) • Modulær RAML ved bruk av Inkluderer, biblioteker, overlegg og utvidelser

• Definer egendefinerte RAML-egenskaper ved hjelp av merknader

1. Oversikt

I RAML-opplæringsartikkelen introduserte vi RESTful API-modelleringsspråk og opprettet en enkel API-definisjon basert på en enkelt enhet som heter Foo. Tenk deg nå en API fra den virkelige verden der du har flere ressurser av enhetstypen, som alle har samme eller lignende GET-, POST-, PUT- og DELETE-operasjoner. Du kan se hvordan API-dokumentasjonen din raskt kan bli kjedelig og repeterende.

I denne artikkelen viser vi hvordan bruken av ressurstyper og trekk funksjoner i RAML kan eliminere permitteringer i ressurs- og metodedefinisjoner ved å trekke ut og parameterisere vanlige seksjoner, og dermed eliminere kopier og lim feil mens API-definisjonene dine blir mer konsise.

2. Vår API

For å demonstrere fordelene med ressurstyper og trekk, vil vi utvide vår opprinnelige API ved å legge til ressurser for en andre enhetstype kalt Bar. Her er ressursene som utgjør vårt reviderte API:

  • GET / api / v1 / foos
  • POST / api / v1 / foos
  • GET / api / v1 / foos / {fooId}
  • PUT / api / v1 / foos / {fooId}
  • SLETT / api / v1 / foos / {fooId}
  • GET / api / v1 / foos / name / {name}
  • GET / api / v1 / foos? Name = {name} & ownerName = {ownerName}
  • GET / api / v1 / barer
  • POST / api / v1 / barer
  • GET / api / v1 / barer / {barId}
  • PUT / api / v1 / barer / {barId}
  • SLETT / api / v1 / barer / {barId}
  • GET / api / v1 / barer / fooId / {fooId}

3. Gjenkjenne mønstre

Når vi leser gjennom listen over ressurser i API-et vårt, begynner vi å se noen mønstre dukker opp. For eksempel er det et mønster for URI-ene og metodene som brukes til å opprette, lese, oppdatere og slette enkeltenheter, og det er et mønster for URI-ene og metodene som brukes til å hente samlinger av enheter. Samlings- og samleobjektmønsteret er et av de vanligste mønstrene som brukes til å trekke ut ressurstyper i RAML-definisjoner.

La oss se på et par deler av API: et:

[Merk: I kodebitene nedenfor indikerer en linje som bare inneholder tre prikker (...) at noen linjer hoppes over for kortfattet.]

/ foos: get: beskrivelse: | Oppgi alle foos som samsvarer med søkekriteriene, hvis de er gitt; Ellers oppgi alle foos queryParameters: navn ?: streng eiernavn ?: streng svar: 200: body: application / json: type: Foo [] post: beskrivelse: Opprett en ny foo body: application / json: type: Foo respons: 201: body: application / json: type: Foo ... / bars: get: beskrivelse: | Oppgi alle søylene som samsvarer med søkekriteriene, hvis de finnes Hvis ikke, list opp alle stolper queryParameters: navn ?: streng eiernavn ?: streng svar: 200: body: application / json: type: Bar [] post: beskrivelse: Opprett en ny bar body: application / json: type: Bar svar: 201: body: application / json: type: Bar

Når vi sammenligner RAML-definisjonene av / foos og / barer ressurser, inkludert HTTP-metodene som brukes, kan vi se flere permitteringer blant de forskjellige egenskapene til hver, og vi ser igjen at mønstre begynner å dukke opp.

Uansett hvor det er et mønster i enten en ressurs- eller metodedefinisjon, er det en mulighet til å bruke en RAML ressurstype eller trekk.

4. Ressurstyper

For å implementere mønstrene som finnes i APIen, ressurstyper bruk reserverte og brukerdefinerte parametere omgitt av doble vinkelparenteser (<>).

4.1 Reserverte parametere

To reserverte parametere kan brukes i definisjoner av ressurstype:

  • <> representerer hele URI (etter baseURI), og
  • <> representerer den delen av URI som følger skråstreket lengst til høyre (/), og ignorerer eventuelle bukseseler {}.

Når de behandles i en ressursdefinisjon, beregnes verdiene deres basert på ressursen som defineres.

Gitt ressursen / foos, for eksempel, <> vil evaluere til “/ foos” og <>vil evaluere til “foos”.

Gitt ressursen / foos / {fooId}, <> vil evaluere til “/ foos / {fooId}” og <>vil evaluere til “foos”.

4.2 Brukerdefinerte parametere

EN ressurstype definisjon kan også inneholde brukerdefinerte parametere. I motsetning til de reserverte parametrene, hvis verdier bestemmes dynamisk basert på ressursen som defineres, må brukerdefinerte parametere tildeles verdier uansett hvor ressurstype inneholder dem, og disse verdiene endres ikke.

Brukerdefinerte parametere kan deklareres i begynnelsen av a ressurstype definisjon, selv om det ikke er nødvendig og ikke er vanlig praksis, da leseren vanligvis kan finne ut av deres tiltenkte bruk gitt navn og sammenhenger de brukes i.

4.3 Parameterfunksjoner

En håndfull nyttige tekstfunksjoner er tilgjengelige for bruk overalt hvor en parameter brukes for å transformere den utvidede verdien til parameteren når den behandles i en ressursdefinisjon.

Her er funksjonene som er tilgjengelige for parametertransformasjon:

  • !singulariser
  • !pluralisere
  • !stor bokstav
  • !små bokstaver
  • !oppercamelcase
  • !senkekoffert
  • !upperunderscorecase
  • !lavereundersøkelse
  • !upperhyphencase
  • !lavere bokstav

Funksjoner brukes til en parameter ved hjelp av følgende konstruksjon:

<<parameternavn | !funksjonsnavn>>

Hvis du trenger å bruke mer enn én funksjon for å oppnå ønsket transformasjon, vil du skille hvert funksjonsnavn med rørsymbolet (“|”) og legge et utropstegn (!) Foran hver funksjon som brukes.

For eksempel gitt ressursen / foos, der <<resourcePathName>> vurderer til "foos":

  • <<resourcePathName | !singulariser>> ==> “foo”
  • <<resourcePathName | !stor bokstav>> ==> “FOOS”
  • <<resourcePathName | !singulariser | !stor bokstav>> ==> “FOO”

Og gitt ressursen / barer / {barId}, der <<resourcePathName>> vurderer til "barer":

  • <<resourcePathName | !stor bokstav>> ==> “BARER”
  • <<resourcePathName | !oppercamelcase>> ==> “Bar”

5. Utpakking av en ressurstype for samlinger

La oss omformere / foos og / barer ressursdefinisjoner vist ovenfor, ved hjelp av a ressurstype for å fange opp de vanlige egenskapene. Vi vil bruke den reserverte parameteren <>, og den brukerdefinerte parameteren <> for å representere datatypen som brukes.

5.1 Definisjon

Her er en ressurstype definisjon som representerer en samling varer:

resourceTypes: collection: bruk: Bruk denne resourceType til å representere en hvilken som helst samling av varebeskrivelse: En samling av <> get: beskrivelse: Få alle <>, valgfritt filtrerte svar: 200: body: application / json: type: <> [] post : beskrivelse: Opprett et nytt <> svar: 201: body: application / json: type: <>

Vær oppmerksom på at i vårt API, fordi datatypene våre bare er store, store versjoner av grunnressursenes navn, kunne vi ha brukt funksjoner på <<resourcePathName>> parameter, i stedet for å introdusere den brukerdefinerte <<typenavn>> parameter, for å oppnå samme resultat for denne delen av API:

resourceTypes: collection: ... get: ... type: <> [] post: ... type: <>

5.2 Søknad

Ved hjelp av definisjonen ovenfor som inneholder <<typenavn>> parameter, her er hvordan du vil bruke "samlingen" ressurstype til ressursene / foos og /barer:

/ foos: type: {collection: {"typeName": "Foo"}} get: queryParameters: name ?: string ownerName ?: string ... / bars: type: {collection: {"typeName": "Bar"} }

Legg merke til at vi fremdeles er i stand til å innlemme forskjellene mellom de to ressursene - i dette tilfellet, queryParameters delen - mens du fremdeles benytter deg av alt det ressurstype definisjon har å tilby.

6. Utvinne en ressurstype for enkeltelementer i en samling

La oss fokusere nå på den delen av API-et vårt som handler om enkeltelementer i en samling: / foos / {fooId} og / barer / {barId} ressurser. Her er koden for/ foos / {fooId}:

/ foos: ... / {fooId}: get: beskrivelse: Få et Foo-svar: 200: body: application / json: type: Foo 404: body: application / json: type: Error example:! inkluderer eksempler / feil. json put: beskrivelse: Oppdater en Foo-kropp: applikasjon / json: type: Foo-svar: 200: kropp: applikasjon / json: type: Foo 404: kropp: applikasjon / json: type: Feileksempel:! inkluderer eksempler / Error.json slett: beskrivelse: Slett et Foo-svar: 204: 404: body: application / json: type: Feileksempel:! inkluderer eksempler / Error.json

De / barer / {barId} ressursdefinisjon har også GET, PUT og DELETE metoder og er identisk med /foos / {fooId} definisjon, annet enn forekomstene av strengene "foo" og "bar" (og deres respektive pluraliserte og / eller store bokstaver).

6.1 Definisjon

Her trekker vi frem mønsteret vi nettopp har identifisert ressurstype for enkeltartikler i en samling:

resourceTypes: ... item: bruk: Bruk denne resourceType til å representere en enkelt varebeskrivelse: En enkelt <> get: beskrivelse: Få et <> svar: 200: body: application / json: type: <> 404: body: application / json: type: Feileksempel:! inkluderer eksempler / Error.json put: beskrivelse: Oppdater et <> body: program / json: type: <> svar: 200: body: application / json: type: <> 404: body : application / json: type: Feileksempel:! inkluderer eksempler / Error.json delete: beskrivelse: Slett et <> svar: 204: 404: body: application / json: type: Error example:! include examples / Error.json

6.2 Søknad

Og her er hvordan vi bruker "varen" ressurstype:

/ foos: ... / {fooId}: type: {item: {"typeName": "Foo"}}
... / barer: ... / {barId}: type: {item: {"typeName": "Bar"}}

7. Egenskaper

Mens en ressurstype brukes til å trekke ut mønstre fra ressursdefinisjoner, a trekk brukes til å trekke ut mønstre fra metodedefinisjoner som er vanlige på tvers av ressurser.

7.1 Parametere

Sammen med <<resourcePath>> og <<resourcePathName>>, er en ekstra reservert parameter tilgjengelig for bruk i definisjoner av egenskaper: <<methodName>> evaluerer til HTTP-metoden (GET, POST, PUT, DELETE, etc) som trekk er definert. Brukerdefinerte parametere kan også vises i en definisjon av egenskaper, og når de brukes, får de verdien av ressursen der de blir brukt.

7.2 Definisjon

Legg merke til at "varen" ressurstype er fortsatt full av permitteringer. La oss se hvordan trekk kan bidra til å eliminere dem. Vi begynner med å trekke ut en trekk for enhver metode som inneholder et anmodningsorgan:

trekk: hasRequestItem: body: application / json: type: <>

La oss nå trekke ut trekk for metoder hvis normale svar inneholder kropper:

 hasResponseItem: svar: 200: body: applikasjon / json: type: <> hasResponseCollection: svar: 200: body: applikasjon / json: type: <> []

Til slutt, her er en trekk for hvilken som helst metode som kan returnere 404 feilrespons:

 hasNotFound: svar: 404: body: application / json: type: Feileksempel:! inkluderer eksempler / Error.json

7.3 Søknad

Vi bruker deretter dette trekk til vår ressurstyper:

resourceTypes: collection: usage: Bruk denne resourceType til å representere enhver samling av varebeskrivelse: En samling av <> get: description: | Få alt <>, valgfritt filtrert er: [hasResponseCollection: {typeName: <>}] post: beskrivelse: Opprett et nytt <> is: [hasRequestItem: {typeName: <>}] element: bruk: Bruk denne ressurstypen til å representere alle enkeltvarebeskrivelse: En enkelt <> get: beskrivelse: Få en <> er: [hasResponseItem: {typeName: <>}, hasNotFound] put: beskrivelse: Oppdater a <> is: | [hasRequestItem: {typeName: <>}, hasResponseItem: {typeName: <>}, hasNotFound] delete: beskrivelse: Slett et <> is: [hasNotFound] svar: 204:

Vi kan også søke trekk til metoder definert innen ressurser. Dette er spesielt nyttig for "engangs" -scenarier der en ressurs-metode-kombinasjon samsvarer med en eller flere trekk men samsvarer ikke med noen definert ressurstype:

/ foos: ... / name / {name}: get: description: Liste alle foos med et bestemt navn er: [hasResponseCollection: {typeName: Foo}]

8. Konklusjon

I denne opplæringen har vi vist hvordan man kan redusere eller i noen tilfeller eliminere permitteringer fra en RAML API-definisjon betydelig.

Først identifiserte vi de overflødige delene av ressursene våre, kjente igjen mønstrene deres og hentet ut dem ressurstyper. Så gjorde vi det samme for metodene som var vanlige på tvers av ressurser for å trekke ut trekk. Da klarte vi å eliminere ytterligere permitteringer ved å søke trekk til vår ressurstyper og til "engangs" ressursmetodekombinasjoner som ikke strengt samsvarte med en av våre definerte ressurstyper.

Som et resultat ble vår enkle API med ressurser for bare to enheter redusert fra 177 til litt over 100 linjer med kode. For å lære mer om RAML ressurstyper og trekk, besøk RAML.org 1.0-spesifikasjonen.

De full gjennomføring av denne veiledningen finner du i github-prosjektet.

Her er vår siste RAML API i sin helhet:

#% RAML 1.0 tittel: Baeldung Foo REST Services API versjon: v1-protokoller: [HTTPS] baseUri: //rest-api.baeldung.com/api/{version} mediaType: applikasjon / json sikretBy: basicAuth securitySchemes: basicAuth: beskrivelse: | Hver forespørsel må inneholde overskriftene som er nødvendige for grunnleggende autentiseringstype: Grunnleggende autentisering beskrevet Av: overskrifter: Autorisasjon: beskrivelse: | Brukes til å sende den påmeldte type "brukernavn: passord" til Base64: type svar: 401: beskrivelse: | Uautorisert. Enten er det oppgitte brukernavnet og passordkombinasjonen ugyldig, eller så får ikke brukeren tilgang til innholdet fra den forespurte URL-en. types: Foo:! include types / Foo.raml Bar:! include types / Bar.raml Error:! include types / Error.raml resourceTypes: collection: use: Bruk denne resourceType til å representere en samling av varebeskrivelse: En samling av < > get: beskrivelse: | Få alt <>, valgfritt filtrert er: [hasResponseCollection: {typeName: <>}] post: beskrivelse: | Opprett et nytt <> is: [hasRequestItem: {typeName: <>}] element: bruk: Bruk denne ressurstypen til å representere en enkelt varebeskrivelse: En enkelt <> get: beskrivelse: Få en <> er: [hasResponseItem: {typeName : <>}, hasNotFound] put: beskrivelse: Oppdater en <> er: [hasRequestItem: {typeName: <>}, hasResponseItem: {typeName: <>}, hasNotFound] delete: description: Slett en <> er: [hasNotFound ] svar: 204: trekk: hasRequestItem: body: application / json: type: <> hasResponseItem: respons: 200: body: application / json: type: <> hasResponseCollection: respons: 200: body: application / json: type: < > [] hasNotFound: svar: 404: body: application / json: type: Feileksempel:! inkluderer eksempler / Error.json / foos: type: {collection: {typeName: Foo}} get: queryParameters: name ?: string ownerName ?: string / {fooId}: type: {item: {typeName: Foo}} / name / {name}: get: description: Liste over alle foos med et bestemt navn er: [hasResponseCollection: {typeName: Foo}] / barer : type: {collecti på: {typeName: Bar}} / {barId}: type: {item: {typeName: Bar}} / fooId / {fooId}: get: description: Få alle stolpene for den matchende fooId er: [hasResponseCollection: {typeName: Bar}]
Neste » Modulær RAML ved bruk av Inkluderer, Biblioteker, Overlegg og Utvidelser « Forrige introduksjon til RAML - RESTful API Modeling Language

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