2. Modelleer de schemas
Nu we een boilerplate OAS hebben, kunnen we deze gaan uitbreiden voor onze eigen specifieke usecase. Eerst gaan we de schemas van de resources modelleren, daarna voegen we extra functionaliteit toe en tenslotte checken we of alles nog aan de API Design Rules voldoet.
OAS wijzigen
Er zijn verschillende manieren om de OAS te wijzigen, maar voor deze tutorial gebruiken we de gratis webversie van Swagger Editor. Hiermee worden aanpassingen aan de OAS direct gevalideerd en gevisualiseerd.
- Open Swagger editor.
- Plak de OAS uit de vorige stap aan de linkerkant van de Swagger editor.
Hier zien we de Swagger Editor met links de OAS-code en rechts de interactieve documentatie.
Swagger editor met links de geplakte input en
rechts de visualisatie van de OAS
Schemas uitbreiden
Zoals gezegd hebben de gegenereerde schemas nu enkel een id property in het
uuid format. Laten we deze gaan uitbreiden met meer informatie.
Tabel
- Bier
- Bierstijl
- Brouwerij
- Adres
| Eigenschap | Type | Formaat | Verplicht | Omschrijving |
|---|---|---|---|---|
| id | string | uuid | Ja | Unieke identifier |
| naam | string | Ja | Naam | |
| alcoholPercentage | number | double | Ja | Alcoholpercentage |
| bierstijl | Bierstijl | Ja | Bierstijl | |
| brouwerij | Brouwerij | Nee | Brouwerij |
| Eigenschap | Type | Formaat | Verplicht | Omschrijving |
|---|---|---|---|---|
| id | string | uuid | Ja | Unieke identifier |
| naam | string | Ja | Naam |
| Eigenschap | Type | Formaat | Verplicht | Omschrijving |
|---|---|---|---|---|
| id | string | uuid | Ja | Unieke identifier |
| naam | string | Ja | Naam | |
| grootte | string | enum | Ja | Grootte brouwerij (hobby/micro/groot) |
| adres | Adres | Nee | Adres |
| Eigenschap | Type | Formaat | Verplicht | Omschrijving |
|---|---|---|---|---|
| straat | string | Ja | Straat van het adres | |
| huisnummer | number | Ja | Huisnummer van het adres | |
| postcode | string | Ja | Postcode van het adres | |
| plaats | string | Ja | Plaats van het adres |
Oplettende lezers zien dat ons Adres schema behoorlijk versimpeld is. Zo
missen we bijvoorbeeld een huisnummertoevoeging. Een écht adresschema bij de
overheid is aanzienlijk complexer. Maar dat is nu precies waarom we voor een
Bier API hebben gekozen: zo kunnen we ons focussen op het leren van de
concepten, zonder te verdwalen in domeinspecifieke complexiteit.
OpenAPI Schema
- Bier
- Bierstijl
- Brouwerij
- Adres
{
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee92"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Weizen Tripel"
},
"alcoholPercentage": {
"type": "number",
"format": "double",
"description": "Alcoholpercentage",
"example": 7.6
},
"bierstijl": {
"$ref": "#/components/schemas/Bierstijl"
},
"brouwerij": {
"$ref": "#/components/schemas/Brouwerij"
}
},
"required": ["id", "naam", "alcoholPercentage", "bierstijl"]
}
{
"description": "Bierstijl",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Quadrupel"
}
},
"required": ["id", "naam"]
}
{
"description": "Brouwerij",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee93"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Brouwtoren"
},
"grootte": {
"type": "string",
"enum": ["hobby", "micro", "groot"],
"description": "Grootte brouwerij (hobby/micro/groot)",
"example": "micro"
},
"adres": {
"$ref": "#/components/schemas/Adres"
}
},
"required": ["id", "naam", "grootte"]
}
{
"description": "Adres",
"properties": {
"straat": {
"type": "string",
"description": "Straatnaam",
"example": "Waldeck Pyrmontsingel"
},
"huisnummer": {
"type": "number",
"description": "Huisnummer",
"example": 12
},
"postcode": {
"type": "string",
"description": "Postcode",
"example": "6521 BC"
},
"plaats": {
"type": "string",
"description": "Plaats",
"example": "Nijmegen"
}
},
"required": ["straat", "huisnummer", "postcode", "plaats"]
}
Voeg voorbeeldwaarden toe voor betere Developer Experience. In de uitgelichte regels zie je hoe we dit hebben gedaan.
Hoewel bovenstaande schemas heel erg lijken op JSON Schema, is het niet 100% hetzelfde. Dit komt doordat OAS 3.0 ouder is dan de officiele release van JSON Schema. Vanaf OAS 3.1 wordt JSON Schema volledig ondersteund, maar deze versie is nog niet goedgekeurd door de Nederlands overheid. Het traject om de verplichte standaard te updaten naar OAS 3.1 loopt momenteel. Zodra OAS 3.1 de nieuwe standaard is zullen we deze tutorial updaten met JSON Schema voorbeelden.
Update de OAS met de schemas
Kopieer elk schema hierboven naar het corresponderende schema in de Swagger
editor. Adres bestaat nog niet, dus die moeten we zelf aanmaken.
De spec zou er op dit moment zo uit moeten zien
{
"openapi": "3.0.2",
"info": {
"title": "Bier API",
"description": "API over bier om te demonstreren hoe je eenvoudig een API kunt ontwikkelen.",
"version": "1.0.0",
"contact": {
"name": "Team developer.overheid.nl",
"email": "developer.overheid@geonovum.nl",
"url": "https://github.com/orgs/developer-overheid-nl/discussions"
}
},
"servers": [
{
"url": "@TODO: Add server URL"
}
],
"tags": [
{
"name": "Brouwerijen",
"description": "Alle API operaties die bij brouwerijen horen."
},
{
"name": "Bieren",
"description": "Alle API operaties die bij bieren horen."
},
{
"name": "Bierstijlen",
"description": "Alle API operaties die bij bierstijlen horen."
}
],
"paths": {
"/brouwerijen": {
"get": {
"operationId": "listBrouwerijen",
"description": "Endpoint om alle brouwerijen op te halen. @TODO: Voeg hier eventueel extra informatie toe over het filteren, pagineren, etc.",
"summary": "Alle brouwerijen ophalen",
"tags": ["Brouwerijen"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
},
"Link": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/Link"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Brouwerij"
}
}
}
}
}
}
},
"post": {
"operationId": "createBrouwerij",
"description": "Nieuwe brouwerij aanmaken",
"summary": "Nieuwe brouwerij aanmaken",
"tags": ["Brouwerijen"],
"responses": {
"201": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Brouwerij"
}
}
}
},
"400": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/400"
}
}
}
},
"/brouwerijen/{id}": {
"parameters": [
{
"$ref": "#/components/parameters/id"
}
],
"get": {
"operationId": "retrieveBrouwerij",
"description": "Brouwerij ophalen",
"summary": "Brouwerij ophalen",
"tags": ["Brouwerijen"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Brouwerij"
}
}
}
},
"404": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/404"
}
}
},
"put": {
"operationId": "editBrouwerij",
"description": "Brouwerij wijzigen",
"summary": "Brouwerij wijzigen",
"tags": ["Brouwerijen"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Brouwerij"
}
}
}
},
"400": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/400"
}
}
},
"delete": {
"operationId": "removeBrouwerij",
"description": "Brouwerij verwijderen",
"summary": "Brouwerij verwijderen",
"tags": ["Brouwerijen"],
"responses": {
"204": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/204"
},
"404": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/404"
}
}
}
},
"/bieren": {
"get": {
"operationId": "listBieren",
"description": "Endpoint om alle bieren op te halen. @TODO: Voeg hier eventueel extra informatie toe over het filteren, pagineren, etc.",
"summary": "Alle bieren ophalen",
"tags": ["Bieren"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
},
"Link": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/Link"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Bier"
}
}
}
}
}
}
},
"post": {
"operationId": "createBier",
"description": "Nieuwe bier aanmaken",
"summary": "Nieuwe bier aanmaken",
"tags": ["Bieren"],
"responses": {
"201": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Bier"
}
}
}
},
"400": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/400"
}
}
}
},
"/bieren/{id}": {
"parameters": [
{
"$ref": "#/components/parameters/id"
}
],
"get": {
"operationId": "retrieveBier",
"description": "Bier ophalen",
"summary": "Bier ophalen",
"tags": ["Bieren"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Bier"
}
}
}
},
"404": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/404"
}
}
},
"put": {
"operationId": "editBier",
"description": "Bier wijzigen",
"summary": "Bier wijzigen",
"tags": ["Bieren"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Bier"
}
}
}
},
"400": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/400"
}
}
},
"delete": {
"operationId": "removeBier",
"description": "Bier verwijderen",
"summary": "Bier verwijderen",
"tags": ["Bieren"],
"responses": {
"204": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/204"
},
"404": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/404"
}
}
}
},
"/bierstijlen": {
"get": {
"operationId": "listBierstijlen",
"description": "Endpoint om alle bierstijlen op te halen. @TODO: Voeg hier eventueel extra informatie toe over het filteren, pagineren, etc.",
"summary": "Alle bierstijlen ophalen",
"tags": ["Bierstijlen"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
},
"Link": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/Link"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Bierstijl"
}
}
}
}
}
}
}
},
"/bierstijlen/{id}": {
"parameters": [
{
"$ref": "#/components/parameters/id"
}
],
"get": {
"operationId": "retrieveBierstijl",
"description": "Bierstijl ophalen",
"summary": "Bierstijl ophalen",
"tags": ["Bierstijlen"],
"responses": {
"200": {
"headers": {
"API-Version": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version"
}
},
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Bierstijl"
}
}
}
},
"404": {
"$ref": "https://static.developer.overheid.nl/adr/components.yaml#/responses/404"
}
}
}
}
},
"components": {
"schemas": {
"Brouwerij": {
"description": "Brouwerij",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee93"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Weizen Tripel"
},
"grootte": {
"type": "string",
"enum": ["hobby", "micro", "groot"],
"description": "Grootte brouwerij (hobby/micro/groot)",
"example": "micro"
},
"adres": {
"description": "Adres",
"properties": {
"straat": {
"type": "string",
"description": "Straatnaam",
"example": "Waldeck Pyrmontsingel"
},
"huisnummer": {
"type": "number",
"description": "Huisnummer",
"example": 12
},
"postcode": {
"type": "string",
"description": "Postcode",
"example": "6521 BC"
},
"plaats": {
"type": "string",
"description": "Plaats",
"example": "Nijmegen"
}
},
"required": ["straat", "huisnummer", "postcode", "plaats"]
}
},
"required": ["id", "naam", "grootte"]
},
"Bier": {
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee92"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Weizen Tripel"
},
"alcoholPercentage": {
"type": "number",
"format": "double",
"description": "Alcoholpercentage",
"example": 7.6
},
"bierstijl": {
"$ref": "#/components/schemas/Bierstijl"
},
"brouwerij": {
"$ref": "#/components/schemas/Brouwerij"
}
},
"required": ["id", "naam", "alcoholPercentage", "bierstijl"]
},
"Bierstijl": {
"description": "Bierstijl",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Unieke identifier",
"example": "046b6c7f-0b8a-43b9-b35d-6489e6daee91"
},
"naam": {
"type": "string",
"description": "Naam",
"example": "Quadrupel"
}
},
"required": ["id", "naam"]
}
},
"parameters": {
"id": {
"name": "id",
"in": "path",
"description": "id",
"required": true,
"schema": {
"type": "string"
}
}
}
}
}
In Swagger editor zien we nu aan de rechterkant de geüpdatete documentatie. In de voorbeeldresponses zien we bovendien waarom we zojuist overal voorbeeldwaarden hebben toegevoegd.
Wat hebben we geleerd?
- Hoe we de Swagger Editor gebruiken om een OAS te bewerken en te visualiseren
- Hoe we schemas definiëren met properties, types en formats
- Hoe we
$refgebruiken om naar andere schemas te verwijzen (zoalsBierstijlenBrouwerijinBier) - Waarom voorbeeldwaarden belangrijk zijn voor een goede Developer Experience
Volgende stap
Onze schemas zijn nu compleet. In de volgende stap gaan we functionaliteit toevoegen aan de API, zoals het filteren van brouwerijen op grootte.