Elimineer overtolligheden in RAML met resourcetypen en eigenschappen

Dit artikel maakt deel uit van een reeks: • Inleiding tot RAML - De RESTful API-modelleringstaal

• Elimineer overtolligheden in RAML met resourcetypen en eigenschappen (huidig ​​artikel) • Modulaire RAML met behulp van inclusief, bibliotheken, overlays en uitbreidingen

• Definieer aangepaste RAML-eigenschappen met behulp van annotaties

1. Overzicht

In ons RAML-zelfstudieartikel hebben we de RESTful API-modelleringstaal en creëerde een eenvoudige API-definitie op basis van een enkele entiteit genaamd Foo. Stel je nu een echte API voor waarin je verschillende bronnen van het entiteitstype hebt, die allemaal dezelfde of vergelijkbare GET-, POST-, PUT- en DELETE-bewerkingen hebben. U kunt zien hoe uw API-documentatie snel vervelend en repetitief kan worden.

In dit artikel laten we zien hoe het gebruik van de resource typen en eigenschappen functies in RAML kunnen elimineer overtolligheden in resource- en methodedefinities door algemene secties te extraheren en te parametreren, waardoor kopieer- en plakfouten worden geëlimineerd terwijl uw API-definities beknopter worden.

2. Onze API

Om de voordelen van resource typen en eigenschappen, zullen we onze oorspronkelijke API uitbreiden door bronnen toe te voegen voor een tweede entiteitstype genaamd Bar. Hier zijn de bronnen waaruit onze herziene API zal bestaan:

  • GET / api / v1 / foos
  • POST / api / v1 / foos
  • GET / api / v1 / foos / {fooId}
  • PUT / api / v1 / foos / {fooId}
  • VERWIJDEREN / api / v1 / foos / {fooId}
  • GET / api / v1 / foos / naam / {naam}
  • GET / api / v1 / foos? Name = {name} & ownerName = {ownerName}
  • GET / api / v1 / bars
  • POST / api / v1 / bars
  • GET / api / v1 / bars / {barId}
  • PUT / api / v1 / bars / {barId}
  • VERWIJDEREN / api / v1 / bars / {barId}
  • GET / api / v1 / bars / fooId / {fooId}

3. Patronen herkennen

Terwijl we de lijst met bronnen in onze API doorlezen, beginnen we enkele patronen te zien ontstaan. Er is bijvoorbeeld een patroon voor de URI's en methoden die worden gebruikt om afzonderlijke entiteiten te maken, lezen, bijwerken en verwijderen, en er is een patroon voor de URI's en methoden die worden gebruikt om verzamelingen entiteiten op te halen. Het patroon van verzameling en verzameling item is een van de meest voorkomende patronen die worden gebruikt om te extraheren resource typen in RAML-definities.

Laten we eens kijken naar een paar secties van onze API:

[Opmerking: in de onderstaande codefragmenten geeft een regel met slechts drie punten (…) aan dat sommige regels worden overgeslagen om het kort te houden.]

/ foos: get: description: | Maak een lijst van alle foos die overeenkomen met de zoekcriteria, indien aanwezig; anders lijst alle foos queryParameters: naam ?: string ownerName ?: string reacties: 200: body: application / json: type: Foo [] post: description: Maak een nieuwe foo body: application / json: type: Foo reacties: 201: body: application / json: type: Foo ... / bars: get: description: | Maak een lijst van alle balken die overeenkomen met de zoekcriteria, indien aanwezig; anders lijst alle balken queryParameters: naam ?: string ownerName ?: string reacties: 200: body: application / json: type: Bar [] post: description: Maak een nieuwe bar body: application / json: type: Bar reacties: 201: body: application / json: type: Bar

Wanneer we de RAML-definities van de / foos en / bars bronnen, inclusief de gebruikte HTTP-methoden, kunnen we verschillende redundanties zien tussen de verschillende eigenschappen van elk, en we zien opnieuw dat patronen naar voren komen.

Overal waar er een patroon is in een resource- of methodedefinitie, is er een mogelijkheid om een ​​RAML te gebruiken resourcetype of eigenschap.

4. Brontypen

Om de patronen in de API te implementeren, resource typen gebruik gereserveerde en door de gebruiker gedefinieerde parameters tussen dubbele punthaken (<>).

4.1 Gereserveerde parameters

Twee gereserveerde parameters kunnen worden gebruikt in definities van resourcetypen:

  • <> vertegenwoordigt de volledige URI (na de baseURI), en
  • <> vertegenwoordigt het deel van de URI dat volgt op de meest rechtse schuine streep (/), waarbij accolades worden genegeerd {}.

Bij verwerking binnen een resourcedefinitie worden hun waarden berekend op basis van de resource die wordt gedefinieerd.

Gezien de bron / foos, bijvoorbeeld, <> zou evalueren naar "/ foos" en <>zou evalueren naar "foos".

Gezien de bron / foos / {fooId}, <> zou evalueren naar "/ foos / {fooId}" en <>zou evalueren naar "foos".

4.2 Door de gebruiker gedefinieerde parameters

EEN resourcetype definitie kan ook door de gebruiker gedefinieerde parameters bevatten. In tegenstelling tot de gereserveerde parameters, waarvan de waarden dynamisch worden bepaald op basis van de resource die wordt gedefinieerd, moeten door de gebruiker gedefinieerde parameters waarden worden toegewezen resourcetype die ze bevat, wordt gebruikt en die waarden veranderen niet.

Door de gebruiker gedefinieerde parameters kunnen aan het begin van een resourcetype definitie, hoewel dit niet vereist is en niet gebruikelijk is, aangezien de lezer meestal het beoogde gebruik kan achterhalen op basis van hun namen en de contexten waarin ze worden gebruikt.

4.3 Parameterfuncties

Een handvol nuttige tekstfuncties is beschikbaar voor gebruik overal waar een parameter wordt gebruikt om de uitgebreide waarde van de parameter te transformeren wanneer deze wordt verwerkt in een resourcedefinitie.

Hier zijn de functies die beschikbaar zijn voor parametertransformatie:

  • !singularize
  • !meervoud
  • !hoofdletters
  • !kleine letters
  • !hoofdletters
  • !onderkast
  • !upperunderscorecase
  • !lowerunderscorecase
  • !hoofdletter
  • !kleine letters

Functies worden toegepast op een parameter met behulp van de volgende constructie:

<<parameternaam | !functienaam>>

Als u meer dan één functie moet gebruiken om de gewenste transformatie te bereiken, scheidt u elke functienaam met het pipe-symbool ("|") en plaatst u een uitroepteken (!) Voor elke gebruikte functie.

Gezien de resource / foos, waarbij <<resourcePathName>> evalueert naar "foos":

  • <<resourcePathName | !singularize>> ==> "foo"
  • <<resourcePathName | !hoofdletters>> ==> "FOOS"
  • <<resourcePathName | !singularize | !hoofdletters>> ==> "FOO"

En gezien de middelen / bars / {barId}, waarbij <<resourcePathName>> evalueert naar "bars":

  • <<resourcePathName | !hoofdletters>> ==> "BARS"
  • <<resourcePathName | !hoofdletters>> ==> "Bar"

5. Een brontype extraheren voor verzamelingen

Laten we het / foos en / bars resourcedefinities hierboven weergegeven, met behulp van een resourcetype om de gemeenschappelijke eigenschappen vast te leggen. We zullen de gereserveerde parameter gebruiken <>, en de door de gebruiker gedefinieerde parameter <> om het gebruikte gegevenstype weer te geven.

5.1 Definitie

Hier is een resourcetype definitie die een verzameling items vertegenwoordigt:

resourceTypes: collection: usage: Gebruik dit resourceType om een ​​verzameling items weer te geven description: Een verzameling van <> get: description: Haal alle <>, optioneel gefilterde reacties op: 200: body: application / json: type: <> [] post : description: Maak een nieuwe <> response: 201: body: application / json: type: <>

Merk op dat in onze API, omdat onze gegevenstypen alleen hoofdletters zijn, enkelvoudige versies van de namen van onze basisbronnen, we functies hadden kunnen toepassen op de <<resourcePathName>> parameter, in plaats van de door de gebruiker gedefinieerde <<typeName>> parameter, om hetzelfde resultaat te bereiken voor dit gedeelte van de API:

resourceTypes: collectie: ... get: ... type: <> [] bericht: ... type: <>

5.2 Toepassing

Gebruikmakend van de bovenstaande definitie waarin de <<typeName>> parameter, hier is hoe u de "collectie" zou toepassen resourcetype naar de bronnen / foos en /bars:

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

Merk op dat we nog steeds in staat zijn om de verschillen tussen de twee bronnen op te nemen - in dit geval de queryParameters -sectie - terwijl u nog steeds profiteert van alles dat de resourcetype definitie te bieden heeft.

6. Een brontype extraheren voor afzonderlijke items van een collectie

Laten we ons nu concentreren op het gedeelte van onze API dat zich bezighoudt met afzonderlijke items van een verzameling: het / foos / {fooId} en / bars / {barId} middelen. Hier is de code voor/ foos / {fooId}:

/ foos: ... / {fooId}: get: description: Krijg een Foo-respons: 200: body: application / json: type: Foo 404: body: application / json: type: Foutvoorbeeld:! include voorbeelden / Fout. json put: description: Update een Foo-body: application / json: type: Foo-reacties: 200: body: application / json: type: Foo 404: body: application / json: type: Foutvoorbeeld:! include voorbeelden / Error.json delete: description: Delete a Foo-antwoorden: 204: 404: body: application / json: type: Error example:! include samples / Error.json

De / bars / {barId} resource-definitie heeft ook GET-, PUT- en DELETE-methoden en is identiek aan de /foos / {fooId} definitie, anders dan het voorkomen van de strings "foo" en "bar" (en hun respectievelijke meervouds- en / of hoofdlettervormen).

6.1 Definitie

Het extraheren van het patroon dat we zojuist hebben geïdentificeerd, hier is hoe we een resourcetype voor losse items van een collectie:

resourceTypes: ... item: usage: Gebruik dit resourceType om een ​​enkele itembeschrijving weer te geven: een enkele <> get: description: een <> -reactie ophalen: 200: body: application / json: type: <> 404: body: application / json: type: Foutvoorbeeld:! include voorbeelden / Error.json put: description: Update een <> body: application / json: type: <> reacties: 200: body: application / json: type: <> 404: body : application / json: type: Fout voorbeeld:! include voorbeelden / Error.json delete: description: Verwijder a <> reacties: 204: 404: body: application / json: type: Fout voorbeeld:! include voorbeelden / Error.json

6.2 Toepassing

En hier is hoe we het ‘item’ toepassen resourcetype:

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

7. Eigenschappen

Terwijl a resourcetype wordt gebruikt om patronen uit resourcedefinities te halen, een eigenschap wordt gebruikt om patronen te extraheren uit methodedefinities die in alle bronnen voorkomen.

7.1 Parameters

Samen met <<resourcePath>> en <<resourcePathName>> is er een extra gereserveerde parameter beschikbaar voor gebruik in kenmerkdefinities: <<methodName>> evalueert naar de HTTP-methode (GET, POST, PUT, DELETE, enz.) waarvoor de eigenschap is gedefinieerd. Door de gebruiker gedefinieerde parameters kunnen ook voorkomen binnen een kenmerkdefinitie en, indien toegepast, de waarde aannemen van de bron waarin ze worden toegepast.

7.2 Definitie

Merk op dat het "item" resourcetype zit nog vol met ontslagen. Laten we eens kijken hoe eigenschappen kan helpen ze te elimineren. We beginnen met het extraheren van een eigenschap voor elke methode die een verzoektekst bevat:

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

Laten we het nu uitpakken eigenschappen voor methoden waarvan de normale reacties lichamen bevatten:

 hasResponseItem: response: 200: body: application / json: type: <> hasResponseCollection: response: 200: body: application / json: type: <> []

Eindelijk, hier is een eigenschap voor elke methode die een 404-foutreactie kan retourneren:

 hasNotFound: response: 404: body: application / json: type: Error example:! include samples / Error.json

7.3 Toepassing

Dit passen we dan toe eigenschap naar onze resource typen:

resourceTypes: collection: usage: Gebruik dit resourceType om een ​​verzameling items weer te geven description: Een verzameling van <> get: description: | Alles ophalen <>, optioneel gefilterd is: [hasResponseCollection: {typeName: <>}] post: description: Maak een nieuwe <> is: [hasRequestItem: {typeName: <>}] item: gebruik: Gebruik dit resourceType om een beschrijving van één item: Een enkele <> get: description: Get a <> is: [hasResponseItem: {typeName: <>}, hasNotFound] put: description: Update een <> is: | [hasRequestItem: {typeName: <>}, hasResponseItem: {typeName: <>}, hasNotFound] delete: description: Verwijder een <> is: [hasNotFound] reacties: 204:

We kunnen ook solliciteren eigenschappen naar methoden die binnen bronnen zijn gedefinieerd. Dit is vooral handig voor ‘eenmalige’ scenario's waarin een combinatie van hulpbronnen en methoden overeenkomt met een of meer eigenschappen maar komt niet overeen met een gedefinieerd resourcetype:

/ foos: ... / name / {name}: get: description: Maak een lijst van alle foos met een bepaalde naam is: [hasResponseCollection: {typeName: Foo}]

8. Conclusie

In deze zelfstudie hebben we laten zien hoe u redundanties van een RAML API-definitie aanzienlijk kunt verminderen of, in sommige gevallen, kunt elimineren.

Eerst hebben we de overtollige delen van onze bronnen geïdentificeerd, hun patronen herkend en geëxtraheerd resource typen. Vervolgens hebben we hetzelfde gedaan voor de methoden die in alle bronnen voor extraheren werden gebruikt eigenschappen. Vervolgens hebben we verdere ontslagen kunnen elimineren door te solliciteren eigenschappen naar onze resource typen en op "eenmalige" combinaties van hulpbronnen en methoden die niet strikt overeenkomen met een van onze gedefinieerde resource typen.

Als gevolg hiervan is onze eenvoudige API met bronnen voor slechts twee entiteiten teruggebracht van 177 naar iets meer dan 100 regels code. Voor meer informatie over RAML resource typen en eigenschappen, bezoek de RAML.org 1.0-specificatie.

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

Hier is onze laatste RAML API in zijn geheel:

#% RAML 1.0 titel: Baeldung Foo REST Services API-versie: v1-protocollen: [HTTPS] baseUri: //rest-api.baeldung.com/api/{version} mediatype: applicatie / json beveiligd Door: basicAuth securitySchemes: basicAuth: beschrijving: | Elk verzoek moet de headers bevatten die nodig zijn voor het basisverificatietype: Basisverificatie beschrevenBy: headers: Autorisatie: beschrijving: | Wordt gebruikt om de Base64-gecodeerde "gebruikersnaam: wachtwoord" -referenties te verzenden type: stringantwoorden: 401: beschrijving: | Ongeautoriseerd. De opgegeven combinatie van gebruikersnaam en wachtwoord is ongeldig, of de gebruiker heeft geen toegang tot de inhoud van de gevraagde URL. types: Foo:! include types / Foo.raml Bar:! include types / Bar.raml Error:! include types / Error.raml resourceTypes: collectie: gebruik: Gebruik dit resourceType om een ​​verzameling items weer te geven beschrijving: Een verzameling van < > get: beschrijving: | Alles ophalen <>, optioneel gefilterd is: [hasResponseCollection: {typeName: <>}] post: description: | Maak een nieuwe <> is: [hasRequestItem: {typeName: <>}] item: gebruik: Gebruik dit resourceType om een ​​enkele itembeschrijving weer te geven: Een enkele <> get: description: Haal een <> is: [hasResponseItem: {typeName : <>}, hasNotFound] put: description: Update een <> is: [hasRequestItem: {typeName: <>}, hasResponseItem: {typeName: <>}, hasNotFound] delete: description: Verwijder een <> is: [hasNotFound ] reacties: 204: traits: hasRequestItem: body: application / json: type: <> hasResponseItem: reacties: 200: body: application / json: type: <> hasResponseCollection: reacties: 200: body: application / json: type: < > [] hasNotFound: response: 404: body: application / json: type: Error example:! include samples / Error.json / foos: type: {collection: {typeName: Foo}} get: queryParameters: name ?: string ownerName ?: string / {fooId}: type: {item: {typeName: Foo}} / name / {name}: get: description: Maak een lijst van alle foos met een bepaalde naam is: [hasResponseCollection: {typeName: Foo}] / bars : type: {collecti on: {typeName: Bar}} / {barId}: type: {item: {typeName: Bar}} / fooId / {fooId}: get: description: Haal alle balken op voor de overeenkomende fooId is: [hasResponseCollection: {typeName: Bar } ]
De volgende » Modulaire RAML met behulp van inclusief, bibliotheken, overlays en uitbreidingen « Vorige inleiding tot RAML - De RESTful API-modelleringstaal