Door Tijmen Wierenga

Developer

De OpenAPI-standaard

Api's gebruiken met minimale inspanning

03-02-2021 • 12:00

133

Multipage-opmaak

Introductie

Werken met api's brengt frustraties met zich mee die veel developers zullen herkennen: onduidelijke documentatie, een respons die niet overeenkomt met de beschrijving in de documentatie, of de documentatie nog handmatig moeten updaten nadat nieuwe functionaliteit is toegevoegd. Ook het ontwikkelen van api’s kent de nodige uitdagingen. Veel van deze frustraties en uitdagingen kunnen worden overwonnen met de OpenAPI-specificatie.

De OpenAPI-specificatie (OAS) doet een poging om rest-api's toegankelijker te maken door ze op een gestandaardiseerde manier te beschrijven. Dit stelt mensen en computers in staat om met minimale inspanning een api te gebruiken. De OAS, die vroeger Swagger heette, heeft onlangs veel aan populariteit gewonnen. Het ecosysteem is enorm gegroeid en daardoor zijn er ontzettend veel tools op de markt gekomen die helpen om stabiele api's te ontwikkelen en te gebruiken. Dat is ook de Nederlandse overheid niet ontgaan. Zij was een early adopter en voegde de OAS al in mei 2018 toe aan haar open ict-standaarden.

Hoe werkt de OpenAPI-specificatie?

Met de OpenAPI-specificatie beschrijf je een api in een OpenAPI-document. Een OpenAPI-document kan worden geschreven in twee verschillende formaten: JSON en YAML.

Een minimaal OpenAPI-document in JSON:

{
  "openapi": "3.0.0",
  "info": {
    "title": "Demo API",
    "version": "1.0",
    "description": "A sample API to describe the super powers of OpenAPI"
  },
  "paths": {}
}

Hetzelfde OpenAPI-document in YAML:

openapi: 3.0.0
info:
  title: Demo API
  version: '1.0'
  description: A sample API to describe the super powers of OpenAPI
paths: {}

Allereerst beschrijven we de versie van de OpenAPI-specificatie die we willen gebruiken. In dit geval definiëren we versie 3.0.0. Zo kunnen we andere tools vertellen welke versie we gebruiken, zodat ze het document op de juiste manier kunnen interpreteren. Vervolgens is basale informatie uitgewerkt in het info-object. De naam van onze api, de huidige versie en een omschrijving.

Het paths-object is op dit moment nog leeg. In het paths-object kunnen operaties worden gespecificeerd. Hier wordt uiteindelijk beschreven wat de nieuwe api allemaal kan. Omdat YAML iets makkelijker leesbaar is, houden we dit formaat voor de rest van dit artikel aan. Er bestaan converters die moeiteloos documenten naar een ander formaat transformeren.

Operaties

Alles wat je kunt met een api, beschrijf je in een operatie. In OpenAPI bestaan die uit twee delen: een path en een http-verb. Stel je voor dat we via onze api een lijst met gebruikers willen ontsluiten. Een logische keus voor een operatie zou in dit geval een get-request zijn op het /users-path:

...
paths:
  '/users':
    get:
      summary: List users
      description: Returns a list of registered users

De operatie heeft nu wel een duidelijke omschrijving, maar het belangrijkste ontbreekt nog: wat wordt er teruggestuurd? Dit kunnen we definiëren in het responses-object. Dat bevat een lijst met objecten die als key een http-statuscode hebben. Een succesvolle response op een get-request heeft normaliter de statuscode 200.

...
paths:
  '/users':
    get:
      summary: List users
      description: Returns a list of registered users
      responses:
        '200':
          description: 'OK'

Hoewel deze beschrijving vertelt hoe een lijst met gebruikers kan worden opgehaald, is nog onbekend wat er wordt teruggestuurd en welke contenttypes, zoals JSON of XML, ondersteund worden. Door een contentobject toe te voegen aan de beschrijving van de ‘200’-response, kan per contenttype een structuur worden gedefinieerd.

...
paths:
   '/users':
     get:
       summary: List users
       description: Returns a list of registered users
       responses:
         '200':
           description: 'OK'
           content:
             'application/json':
             ...
             application/xml:
             ...

Om de datastructuur te beschrijven, wordt gebruikgemaakt van het Schema Object, dat is geïnspireerd op JSON Schema. Voor ons voorbeeld kiezen we ervoor om de output een array te laten zijn van gebruikers. Iedere gebruiker heeft een unieke username.

...
paths:
  '/users':
    get:
      summary: List users
      description: Returns a list of registered users
      responses:
        '200':
          description: 'OK'
          content:
            'application/json':
              schema:
                type: array
                items:
                  type: object
                  properties:
                    username:
                      type: string
                  required:
                    - username

Een response op een request naar GET /users zou er volgens onze beschrijving als volgt uitzien:

[
  {
    "username": "crisp"
  },
  {
    "username": "ACM"
  },
  {
    "username": "tijmenwierenga"
  }
]

Design first versus code first

Tot nu toe hebben we gewerkt vanuit de 'design first'-filosofie. Voordat we de code hebben geschreven, is gespecificeerd hoe onze api zou moeten werken. Het grootste voordeel hiervan is dat je de requirements van een api kunt uitwerken voordat je werkt aan een implementatie. Dit geeft gebruikers van de api de kans om alvast te werken aan hun kant van de implementatie. Dit kan omdat zij aan de hand van het OpenAPI-document weten welke endpoints ze moeten aanroepen en welke responses ze kunnen verwachten.

Het tegenovergestelde van ‘design first’ is 'code first'. Hier werk je eerst de code uit en beschrijf je achteraf pas hoe je datastructuur eruitziet. Op die manier kunnen ook bestaande api’s met terugwerkende kracht worden beschreven met de OAS. Voorstanders van ‘code first’ geven vaak als argumenten dat ze zo sneller kunnen ontwikkelen en dat het niet zoveel uitmaakt dat de documentatie later wordt geschreven. Het is echter twijfelachtig of dit ook in de praktijk opgaat.

Achteraf documentatie genereren is lastig en tijdrovendDe feedbackloop vindt bij ‘code first’ later plaats dan bij ‘design first’. Dit houdt in dat de consumenten van de api pas feedback kunnen geven als de code al geschreven is. Eventuele wijzigingen worden zo al snel kostbaar; de wijzigingen moeten getest worden en opnieuw worden gedeployed. Gebruikers moeten de wijzigingen vervolgens zelf testen en kunnen weer met nieuwe feedback komen. Met een ‘design first’-aanpak is dit veel goedkoper. De specificaties kunnen worden gedeeld met de consument voordat er een regel code is geschreven. Als de specificatie is beschreven met OAS, kan de integratie zelfs al getest worden door middel van een mockserver. Dat is een speciale server die dummydata teruggeeft aan de hand van een OpenAPI-specificatie.

“We schrijven de documentatie later wel” betekent in de praktijk vaak: “We schrijven geen documentatie”. Achteraf documentatie genereren is lastig en tijdrovend. In de code moet worden gezocht welke operaties allemaal mogelijk zijn en hoe de bijbehorende requests en responses eruit moeten zien. En met een beetje pech komen er tijdens het ontwikkelen van de documentatie nog nieuwe featurerequests binnen, waardoor de nieuwe documentatie nog steeds niet overeenkomt met de code.

Automatisch documentatie genereren

Om gebruikers de mogelijkheden van een api te laten ontdekken, is het mogelijk om overzichtelijke documentatie te genereren aan de hand van een OpenAPI-document. Er zijn diverse tools in het OpenAPI-ecosysteem die daar ondersteuning voor bieden. Deze tools lezen het OpenAPI-document uit en kunnen zodoende alle mogelijke operaties overzichtelijk weergeven. Voor dit voorbeeld wordt gebruikgemaakt van Redoc, met ruim elfduizend stars op Github een van de populairste libraries met betrekking tot het genereren van documentatie op basis van OAS. Het wordt onder andere gebruikt om de Docker Engine API te documenteren.

Redoc is gebouwd in React. Een van de manieren om het te gebruiken is door de React-library in te laden via een cdn. Voor deze demo heb ik de specificatie geüpload als Github-gist. Onderstaand HTML-document is voldoende om onze documentatie te renderen in een browser.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>API Docs</title>
</head>
<body>
<redoc spec-url="https://gist.githubusercontent.com/TijmenWierenga/
53975a5e8dd3395437be3d6399ef5f46/raw/d0faf2f3bbd482cea952b4a57bcce8ef6fce0876/
openapi.yaml"></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js">
</script>
</body>
</html>

Het resultaat ziet er zo uit in de browser:

Redoc OpenAPI documentatie

Mockservers

Nu consumenten toegang hebben tot het OpenAPI-document, kunnen ze tools gebruiken om de integratie met een api zo makkelijk mogelijk te maken. Een van de manieren om de integratie te testen, is door een mockserver te gebruiken. Een mockserver ontvangt een request van een client en kijkt of het request gematcht kan worden met een van de beschreven operaties.

GET /users
Accept: application/json

In dit geval wordt onze zojuist beschreven operatie opgevraagd en wenst de client een response te ontvangen in JSON. De mockserver leest in het OpenAPI-document uit wat de structuur moet zijn van de data en geeft een gefabriceerde response met dummydata terug.

OpenAPI Mock Service Flowchart

Een van de populairste mockservers is Prism. Het is gebouwd als NodeJS-applicatie, leest OpenAPI-documenten uit en transformeert ze in een mockserver. Onderstaand commando start een mockserver van onze demo-api. De default host is 127.0.0.1:4010.

prism mock -d https://gist.githubusercontent.com/TijmenWierenga/
53975a5e8dd3395437be3d6399ef5f46/raw/d0faf2f3bbd482cea952b4a57bcce8ef6fce0876/
openapi.yaml

Als alles correct verlopen is, laat Prism weten dat de server gestart is en welke operaties beschikbaar zijn.

[7:12:52 PM] › [CLI] …  awaiting  Starting Prism…
[7:12:53 PM] › [CLI] ℹ  info      GET        http://127.0.0.1:4010/users
[7:12:53 PM] › [CLI] ▶  start     Prism is listening on http://127.0.0.1:4010

Als je via de browser of een http-client http://localhost:4010/users bezoekt, geeft de mockserver een response terug aan de hand van onze OpenAPI-specificatie. Mijn response zag er zo uit:

[
  {
    "username": "aliquip dolore culpa ad"
  },
  {
    "username": "minim cillum cu"
  },
  {
    "username": "amet occaecat tempor pariatur"
  }
]

Toekomstige gebruikers van onze api kunnen nu alvast de implementatie aan hun kant doen en hoeven uiteindelijk alleen de URL te veranderen in de URL waar de daadwerkelijke implementatie komt te staan. Hierdoor kunnen wij rustig verder werken aan onze eigen implementatie en hoeven onze gebruikers niet op ons te wachten. Tijdwinst!

Validatie

Een OpenAPI-document kan ook helpen met het specificeren van validatieregels voor data. Het valideren van data in een applicatie verloopt in twee stappen: het valideren van de datastructuur van de ingestuurde data en het valideren van de correctheid van deze data.

Tijdens het valideren van de datastructuur wordt gekeken of alle benodigde data beschikbaar is en of die in de juiste structuur is aangeleverd om een operatie voort te zetten. Stel je voor dat een api een operatie ondersteunt die het mogelijk maakt om een nieuwe gebruiker te registreren op basis van een unieke gebruikersnaam en een veilig wachtwoord van minimaal acht tekens. Op basis van de ruwe data kunnen we het request al valideren op diverse aspecten:

  • Zijn in het request een gebruikersnaam en een wachtwoord meegestuurd?
  • Zijn beide waarden van het datatype 'string'?
  • Is het wachtwoord minimaal acht tekens lang?

Is er een aspect waaraan de data niet voldoet, dan kan de validatie vroegtijdig falen. Api's geven in dit geval vaak een response terug met de 422 Unprocessable Entity-statuscode.

Er is echter nog één ander scenario dat nu niet gevalideerd is: de uniciteit van de gebruikersnaam. Om dit te kunnen valideren, moet worden gekeken of de ingevoerde gebruikersnaam voorkomt in een lijst met al geregistreerde gebruikers. Omdat dit niet kan op basis van enkel de ingevoerde data van de gebruiker, valt het in de tweede categorie: het valideren van de correctheid van de data. Vanwege de afhankelijkheid van externe data kan een OpenAPI-document hier niet bij helpen. Alle andere validatie kan plaatsvinden door de data te beschrijven.

Om deze validatieregels in het OpenAPI-document te verwerken, moet ook het Request worden beschreven. Dat gebeurt net als bij de Response met een Schema Object:

paths:
  /users:
    post:
      summary: Register new user
      operationId: post-users
      responses:
        '201':
          description: Created
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
                password:
                  type: string
                  minLength: 8
                  format: password
              required:
                - username
                - password
      description: Registers a new user

In traditionele applicaties die niet beschreven zijn met een OpenAPI-document, moeten de validatieregels worden gedupliceerd. Aan de kant van de client en aan de kant van de server moet dezelfde datastructuur worden gevalideerd. Door OpenAPI-validators in te zetten kan het proces van validatie van de datastructuur volledig worden geautomatiseerd. Zo kunnen api’s ervoor kiezen om een request alleen te accepteren als de validatie op basis van het OpenAPI-document slaagt. Api’s kunnen bijvoorbeeld proxymiddleware gebruiken die de validatie doet op basis van een OpenAPI-document en een http-request. Voordat het request naar de api gaat, belandt het in deze proxy. De proxy valideert dit request vervolgens. Als de validatie slaagt, wordt het request doorgegeven aan de api om te worden afgehandeld. Slaagt de validatie niet, dan stuurt de proxy een foutmelding terug en belandt het request niet bij de api. De onderstaande afbeelding illustreert hoe validatie op basis van proxymiddleware werkt.

OpenAPI middleware

Zoals te zien in bovenstaande afbeelding wordt een request gestuurd met de intentie om een nieuwe gebruiker aan te maken. Voordat het request naar de applicatie gaat, komt het langs de proxymiddleware. Deze middleware zoekt het schema voor de requestbody op aan de hand van de operatie (POST /users). In het voorbeeld heeft de gebruiker een wachtwoord opgegeven (“short”) dat minder lang is dan de minimale vereiste van acht tekens. De proxymiddleware grijpt in door verdere afhandeling af te breken en laat de server een response (422 Unprocessable Entity) terugsturen met daarin een gedetailleerde foutmelding.

Sommige OpenAPI-validators kunnen worden gebruikt in de applicatie zelf. In dat geval roept de applicatie zelf de validator aan. De principes blijven gelijk. De validator ontvangt het request en bepaalt aan de hand van het gedefinieerde schema of de datastructuur voldoet. De applicatie kan dan vervolgens zelf besluiten om het request voort te zetten of af te breken op basis van het resultaat van de validatie.

Welke manier je ook gebruikt om je data te valideren op basis van een OpenAPI-document, het resultaat is dat de datastructuur geautomatiseerd wordt gevalideerd zonder dat een applicatie deze regels hoeft te dupliceren.

Je kunt een OpenAPI-specificatie zien als een contract tussen leverancier en consumentAls het OpenAPI-document wordt gebruikt als source of truth voor de validatieregels, wordt het wijzigen van regels versimpeld. Stel je voor dat om veiligheidsredenen het minimale aantal tekens van een wachtwoord van acht naar twaalf gaat. Door enkel het juiste schema aan te passen in het OpenAPI-document is deze regel doorgevoerd voor zowel de client als de server en is ook meteen je api-documentatie aangepast.

Het valideren van data op basis van een OpenAPI-document geldt niet alleen voor requests, maar ook voor responses. Je kunt een OpenAPI-specificatie zien als een contract tussen leverancier en consument. Om te voorkomen dat een api een response teruggeeft die niet overeenkomt met de OpenAPI-specificatie, kan de response worden gevalideerd op de manier waarop ook een request wordt gevalideerd. De daadwerkelijke response wordt dan vergeleken met de response die in het OpenAPI-document wordt beschreven. Dit kan bijvoorbeeld in de vorm van geautomatiseerde tests. Deze tests sturen requests naar de api en valideren of de responses overeenkomen met de specificatie.

Een andere optie is het introduceren van middleware die de response valideert. Tijdens het ontwikkelen van de api kan deze middleware een foutmelding geven wanneer de response afwijkt van de specificatie. In een productieomgeving zou iedere afwijking gelogd kunnen worden.

Overige toepassingen

Stoplight Studio - Grafische interface om api's te ontwerpen

Niemand houdt ervan om grote documenten te schrijven in JSON of YAML; het is foutgevoelig en kost veel tijd. Grafische interfaces als Stoplight Studio lossen die problemen op. Stoplight Studio is een api-designtool die het genereren van een OpenAPI-document makkelijker en sneller maakt.

Stoplight Studio API Design GUI

Bovendien biedt Stoplight Studio nog enkele andere voordelen. Zo kun je makkelijk met verschillende mensen samenwerken en push je nieuwe changes vanuit de gui naar sourcecontrol. Ook heeft Stoplight Studio een ingebouwde mockserver en een linter om consistentie af te dwingen.

Nog meer toepassingen

Het automatisch genereren van documentatie, het inzetten van mockservers en het automatisch valideren van requests zijn slechts enkele voorbeelden van hoe de OpenAPI-specificatie kan helpen bij het standaardiseren van api’s. Er zijn nog een hoop andere toepassingen van de OpenAPI-specificatie, zoals contracttesting en het automatisch genereren van sdk’s. Op https://openapi.tools is een lange lijst te vinden met tools die kunnen helpen om het maximale uit een OpenAPI-document te halen.

Tutorial

Om te illustreren hoe een OpenAPI-specificatie van waarde kan zijn in een echte applicatie, heb ik de theorie die in dit artikel is besproken, verwerkt in een api. De broncode van deze api heb ik geüpload op GitHub. Als je het leuk vindt om je handen vuil te maken, kun je de broncode downloaden en de api op je eigen computer draaien. Het vereist wel wat kennis van de commandline. Op de GitHub-pagina wordt uitvoerig beschreven hoe je dit voor elkaar krijgt. Als je alle stappen volgt, heb je lokaal een api, een mockserver en de bijbehorende api-documentatie tot je beschikking. Hieronder volgt een tutorial waarin de api ontdekt en verder ontwikkeld wordt.

De infrastructuur

De basis van de api is uiteraard de OpenAPI-specificatie. De specificatie is opgeslagen in reference/demo-api.v1.yaml. Alle tools maken gebruik van dit bestand als basis voor hun functionaliteit.

Infrastructuur OpenAPI project

De api-documentatie bekijken

Als je een lokale omgeving hebt gestart, is de api-documentatie (Redoc) te bekijken op http://localhost:8080. Hier kun je zien dat er momenteel drie endpoints beschreven zijn:

  • GET /users - Een lijst met gebruikers opvragen
  • POST /users - Een nieuwe gebruiker registreren
  • GET /users/{username} - Een individuele gebruiker opvragen

Requests maken

Requests kunnen gedaan worden aan zowel de mockserver (http://localhost:3100) als de api-server (http://localhost). Als voorbeeld wordt gebruikgemaakt van cURL, een commandlinetool die http-requests kan maken. Je kunt ook gebruikmaken van een http-client met een grafische interface, zoals Postman. Een voordeel van een http-client als Postman is dat je de OpenAPI-specificatie kunt importeren, zodat alle requests geconfigureerd worden.

Om een lijst met gebruikers op te halen via de mockserver, maken we het volgende request:

curl http://localhost:3100/users

De response zal er zo uitzien:

[
  {
    "username": "string"
  }
]

Prism genereert een response op basis van het schema van het OpenAPI-document. Het is mogelijk om meer dynamische en realistische data op te vragen door een Prefer-header mee te sturen.

curl -H 'Prefer: dynamic=true' http://localhost:3100/users

De response wordt dan gegenereerd met dynamische voorbeelden.

[
  {
    "username": "Halie_Champlin"
  },
  {
    "username": "Leora_Walker"
  },
  {
    "username": "Ashly_Hackett"
  }
]

De api-server kunnen we op dezelfde manier raadplegen.

curl http://localhost/users

Het resultaat is een lege array. Op dit moment is er nog geen enkele gebruiker geregistreerd.

Een nieuwe gebruiker registreren

Zoals beschreven in de OpenAPI-specificatie kunnen we een nieuwe gebruiker registreren door een POST-request te doen aan het /users-endpoint met daarin een gebruikersnaam en wachtwoord van minimaal acht tekens.

Zowel de mockserver als de api-server maakt gebruik van validatie op basis van het OpenAPI-document. Om te verifiëren dat beide servers dat doen, kunnen we een request sturen met verkeerde data.

In het eerste voorbeeld sturen we een te kort wachtwoord mee.

curl -X POST -H "Content-Type: application/json" -d '{"username": "tijmen",
"password": "short"}' http://localhost:3100/users

curl -X POST -H "Content-Type: application/json" -d '{"username": "tijmen",
"password": "short"}' http://localhost/users

Hoewel de responsebody niet volledig overeenkomt tussen beide servers, geven ze beide een 422 Unprocessable Entity-statuscode terug met de correcte foutmelding.

Een request dat overeenkomt met het gedefinieerde schema, geeft wel de verwachte response terug met een 201 Created-statuscode:

curl -X POST -H "Content-Type: application/json" -d '{"username": "tijmen",
"password": "long-password"}' -i http://localhost:3100/users

curl -X POST -H "Content-Type: application/json" -d '{"username": "tijmen",
"password": "long-password"}' -i http://localhost/users

Als je het request herhaalt, stuit je op het essentiële verschil tussen een mockserver en de daadwerkelijke api-server. Bij zowel de mockserver als de daadwerkelijke api-server slaagt de requestvalidatie. De mockserver geeft opnieuw een succesvolle response, maar de api-server faalt. Dit gebeurt doordat de api-server naast schemavalidatie ook nog businessregels valideert. Zoals eerder uitgelegd, kunnen deze regels niet door middel van een OpenAPI-document worden beschreven. Dit is de reden dat je niet je volledige validatie kunt doen op basis van een OpenAPI-document.

Het OpenAPI-document aanpassen

Verander in reference/demo-api.v1.yaml op regel 95 de minLength van het wachtwoord naar 12 en sla vervolgens het document op.

Als je de documentatiepagina ververst, is direct te zien dat de validatieregel is aangepast naar de nieuwe waarde. Ook de mockserver en de api-server hebben de nieuwe regel direct geadopteerd.

Om dat te bewijzen, sturen we nogmaals een request naar het POST /users-endpoint met een wachtwoord van elf tekens.

curl -X POST -H "Content-Type: application/json" -d '{"username": "tijmen",
"password": "12345678910"}' http://localhost:3100/users

Dit is de daadwerkelijke kracht van de OpenAPI-specificatie. Wijzigingen worden doorgevoerd in al onze services vanuit een OpenAPI-document.

Een nieuw endpoint toevoegen

Als laatste onderdeel van deze tutorial zetten we een nieuw endpoint op om informatie op te vragen over de auteur van de api. Het doel is om een endpoint op te zetten waarmee je via een get-request op /author informatie over jezelf teruggeeft.

Vanuit de 'design first'-filosofie specificeren we eerst hoe de response eruit moet zien. In dit voorbeeld geven we onze naam en ons e-mailadres terug. Laten we dit vastleggen in het OpenAPI-document (reference/demo-api.v1.yaml).

paths:
  ...
  /author:
    get:
      summary: Information about the author
      operationId: get-author
      description: Returns the name and email address of the author of this API
      responses:
        '200':
          description: 'OK'
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                    description: Name of the author
                  email:
                    type: string
                    format: email
                    description: Email address of the author
                required:
                  - name
                  - email

Om te testen of het request er goed uitziet, sturen we een http-request naar het nieuwe endpoint via de mockserver.

curl -H 'Prefer: dynamic=true' http://localhost:3100/author

Als laatste stap moeten we het endpoint nog implementeren in de daadwerkelijke api. Voeg de volgende codesnippet toe aan public/index.php boven het $app->run()-statement.

$app->get('/author', function (Request $request, Response $response): Response {
    $response->getBody()->write(json_encode([
        'name' => 'Jouw naam',
        'email' => 'jouw_email@example.com',
    ], JSON_THROW_ON_ERROR));
 
    return $response->withStatus(200);
});

Maak vervolgens een request aan het nieuwe endpoint.

curl http://localhost/author

Als alles goed is gegaan, geeft de api nu de response terug die jij hebt geconfigureerd.

Dit was het laatste onderdeel van deze tutorial. Hiermee heb ik geprobeerd een zo goed mogelijke introductie te geven van de OpenAPI-specificatie. Mocht je desondanks nog vragen hebben, laat het dan weten in de comments. Ik zal proberen de meeste vragen te beantwoorden.

Reacties (133)

133
131
89
12
0
40
Wijzig sortering
Zelf hebben wij GraphQL geimplementeerd, wat echt een fluitje van een cent was. Was heel mooi te retrofitten op onze oude API. Voordelen: 1 endpoint, client kan precies ophalen wat ie wil, typed, en automatische documentatie.

Ik ben benieuwd hoe OpenAPI zich tot GraphQL verhoudt, want dat werd me niet duidelijk in het artikel.
GraphQL is een type api, vergelijkbaar met RPC,REST,SOAP.
OpenAPI is alleen een manier om een api te beschrijven, onafhankelijk van hoe je deze api opzet. Normaliter gebruik je het voor rpc/REST api's maar als je echt graag zou willen zou je ook een graphQL of SOAP api in OpenAPI kunnen beschrijven. Niet dat je dat moet willen want SOAP en graphQL hebben daar hun eigen betere manier voor.

Dat toont mijns insziens ook de zwakte van openAPI, je kan er een prachtig gedocumenteerde prut-API mee maken, er is niets wat afdwingt dat die api zich bijvoorbeeld aan REST principes houdt.
Ik begrijp hoe je dat kan zien als een zwakte, maar tegelijkertijd zou je dat ook kunnen zien als een kracht. Het geeft je ook de mogelijkheid om een ouderwetse API te specificeren. Hoe slecht je API ook is, de tools in het OpenAPI ecosysteem zullen met je specificatie kunnen werken.
En dat is precies wat ik een paar maanden heb moeten doen. Nog nooit gewerkt met OpenAPI, heb een API in het systeem dat al 5+ jaar oud is, maar kon het na wat uitzoeken prima beschrijven.
Blijkbaar kun je die in Azure zo inladen, en is het geen programmeerwerk meer om een API te integreren maar configuratie werk.
Klopt. De meeste APi gateways ondersteunen het. Maakt je leven een stuk makkelijker.
Daarbij is het ook een hele nuttige specificatie om dingen mee te automatiseren.
Ik genereer automatisch de specificatie op basis van endpoints en dergelijke. Vervolgens kijk ik in een CI/CD pipeline of wijzigingen wel backwards compatible zijn. Scheelt weer boze klanten aan de lijn.
Stukje achtergrond over verschillende maturity levels: https://martinfowler.com/...hardsonMaturityModel.html. Je kunt OpenAPI prima gebruiken om level-3 api's te maken, ten koste van wat flexibiliteit. Als je greenfield begint, is dat vaak geen probleem.
Wat ik mis in OpenAPI en andere API documentatie tools, is hergebruik van overkoepelende API-modellen.

Stel nu dat ik een bepaald model wil ontsluiten via REST en Messaging (RabbitMQ of Kafka), dan kan ik dat niet goed via OpenAPI beschrijven. In plaats daarvan kan ik AsyncAPI gebruiken, maar die mist dan weer de volwassenheid van code generators die OpenAPI heeft.

De workaround die wij nu gebruiken is om entiteiten die alleen voor Messaging gebruikt worden, er gewoon bij te zetten in het OpenAPI model terwijl ze soms niet voor REST calls worden gebruikt. Op die manier wordt er wel code voor gegenereerd die wij kunnen gebruiken en hebben we die entiteiten tenminste ergens gedocumenteerd.

Het zou mooi zijn als er een keer een overkoepelende API tool zou zijn met goede code generatoren waarmee je entiteiten kunt hergebruiken voor verschillende formaten, dat je bijv. een REST API hebt, maar ook een GraphQL API en dingen via Messaging.
Ja, daar heb je bijvoorbeeld JSONApi voor: https://jsonapi.org/
Ja, daar heb je bijvoorbeeld JSONApi voor: https://jsonapi.org/
Daar?
Herkenbaar, Ik heb zelf ook een GraphQL endpoint voor de backend zitten. Als je er mee hebt gewerkt wil je niet meer terug. Zeker als back end developer kan je meer tijd besteden aan back end functionaliteit en de API loopt veel makkelijker mee en idd de documentatie gaat vanzelf. Aanrader en tip om eens verder te onderzoeken.

Over Caching kan je een boek schrijven dus ik wil alleen zeggen dat je prima caches kan met GraphQL zelfs op query niveau, het kan dus prima ook met GraphQL. Maar niet precies zoals je dat misschien met REST gewend bent. :)
Als documentatie een issue is kun je altijd kijken naar HATEOAS. Icm iets als spring data hoef je dan eigenlijk niks meer te doen.

Met een HAL browser kun je dan een grafische interface als documentatie presenteren waarbij je ook in die ui direct wat calls kunt proberen.

API ontwikkeling is dan supersimpel. Letterlijk een call toevoegen in je repository die je data uit de db trekt en je endpoint wordt er omheen gegoten.

Nieuw call toevoegen is dan dus letterlijk een one-liner.

Zelf een tijd api specs gespecificeerd waarbij OAS gebruikt werd om de API te genereren. Dat is ook een handige manier. Loopt je documentatie nooit achter op je code.
Bedankt voor de tip, over het algemeen kan je denk ik wel stellen dat voor veel “aandachtspunten” van REST wel een externe oplossing is. Wat ik persoonlijk mooi vindt aan GraphQL is dat deze oplossingen veelal in GraphQL zelf zitten. Je hebt daarom niets extra’s nodig voor een mooi implementatie. :)
GraphQL is een mooie ontwikkeling zeker, echter zitten ook daar haken en ogen aan het gebruik ervan. Het 1 sluit overigens het ander niet uit.

Wij gebruikten GQL als backend<->db ontkoppeling. Kon je iedere willekeurige db adapter eraan hangen en zo niet nog een keer je informatiedefinities uit te drukken in specifieke schema’s.
Helemaal eens en leuk om te zien dat jullie er ook mee bezig zijn. Naar mijn ervaring zijn er geen silver bullets bunnen de IT, iedere oplossing heeft zo zijn toepassingen. Echter zou het wel goed zijn als wat meer mensen GraphQL als oplossing in hun virtuele gereedschapskist zouden stoppen denk ik.
Als dev is het sws goed om er eens mee gespeeld te hebben. Goed boor de toolkit idd. Ik zit alleen vaak op toepassingen met grote partijen waar veelal rest de betere oplossing is. Daarom was het wel leuk om er mee te kunnen spelen.
Terechte vraag :) .

Ik heb zelf onvoldoende kennis van GraphQL om daar een eerlijke vergelijking over te doen. Op https://apisyouwonthate.c...ng-the-right-api-paradigm staat een mooie flowchart waarin wordt uitgewerkt wat afwegingen zouden kunnen zijn om te kiezen voor REST, GraphQL or gRPC.

In het algemeen hebben REST API's betere mogelijkheden tot caching. Wanneer de API op generieke wijze gebruikt wordt heeft dit voordelen. Wanneer iedere client een eigen use-case kan hebben, ben je waarschijnlijk meer gebaat bij een GraphQL oplossing.

[Reactie gewijzigd door tijmenwierenga op 24 juli 2024 04:45]

Bedankt voor je reactie. Je caching opmerking kan ik me wel in vinden, alhoewel dat enorm afhangt van de use-case natuurlijk en het data-model welke je modeleert. Maar ik denk dat je wel kan generaliseren dat caching voor REST wellicht makkelijker is dan voor GraphQL.
Mag ik vragen of je liever een GraphQL of REST api hebt van een derde partij?
Bijvoorbeeld je bank of pensioenfonds?
Het hangt heel erg af je use-case.

In GraphQL kun je de data opvragen op de manier waarop jij dat wil. Dat kan het implementeren makkelijker maken. Vroeger had dat als bijkomend voordeel dat je veel informatie met een enkel request kon opvragen. REST API's moesten vaak meerdere requests doen om alle informatie bij elkaar te verzamelen. Dat vertraagde een hoop. Met de komst van HTTP/2 is dat probleem gelukkig opgelost.

Ik denk dat het consumeren van een API gemiddeld genomen iets prettiger is met GraphQL. Toch zijn er hele gegronde redenen voor een API ontwikkelaar om toch een REST API aan te bieden. Onder andere server-side caching is gemiddeld genomen beter te implementeren.

Deze blogpost gaat dieper in op de verschillen tussen REST en GraphQL: https://apisyouwonthate.com/blog/graphql-vs-rest-overview
Met de komst van HTTP/2 is dat probleem gelukkig opgelost.
Qua HTTP overhead misschien, maar wat ik persoonlijk belangrijker vindt is hoeveel moeite je als developer moet doen om alle data op te halen en / of te filteren; dat is met GraphQL een stuk eenvoudiger.
Dat ben ik met je eens. Daarin blinkt GraphQL uit.

Er zijn wel tools in het ecosysteem die proberen het ophalen van data via REST API's makkelijker. Vulcain (https://github.com/dunglas/vulcain) maakt het bijvoorbeeld mogelijk om REST API's te consumeren zoals je dat zou doen in GraphQL.
Vulcain heeft hetzelfde probleem als zijn Mercure. Één persoon ontwikkelt een protocol om er geld aan te verdienen. Natuurlijk is de standaard open, maar de Enterprise solutions voor scalability niet.

Wij hebben zijn Mercure in een project gebruikt waarna hij volledig de spec wijzigde en de database storage enkel via zijn betaalde cloud oplossing liep.

Dus wees gewaarschuwd.
Dat ligt overigens geheel aan het api design. Binnen de overheid staat OAS 3 op de “pas toe of leg uit” lijst en dan krijg je dus dat men oude soap achtige REST api’s gaat documenteren in OAS. Dan is filtering een drama (het feit dat je datamutatie op een GET endpoint kunt doen met een queryparameter daargelaten).

Met een goede restful implementatie gaat dat supersimpel.
Ne dat snap ik, ik vraag mij af of API consumers het hebben van een GraphQL endpoint interessant zouden vinden.
Ligt eraan waar ze de rest van hun externe api’s mee consumeren. Als dat graphQL schemas zijn dan is OAS niet heel handig.
Tegenwoordig zijn er ook genoeg tools te vinden om REST API's zo te maken dat je enkel de data ophaalt die je nodig hebt. Kijk bijvoorbeeld eens naar https://www.odata.org/
Volgens mij is OData al wat ouder dan GraphQL. Ik heb het veel gebruikt icm SAP Gateway
OData is in feite een soort van GraphQL, maar dan over REST. Het bestaat al veel langer en is nooit echt doorgebroken. Zoals veel Microsoft-standaarden van weleer is het vooral "over-engineered". GraphQL is duizend maal eleganter en heeft in korte tijd een vrij volwassen eco-systeem voortgebracht. GraphQL is gemaakt om in dienst van de front-end / UI-laag te staan, OData absoluut niet.
In principe zou het helemaal niets uit moeten maken. Het gaat uiteindelijk om de implementatie.
Voor een mens is een REST API m.i. beter te begrijpen (e.g. /users geeft de gebruikers), maar GraphQL heeft qua programmeren dan juist weer voordelen (automatische typing en documentatie).

Ik heb onlangs GraphQL opgepakt (na lang uitstellen want het leek te ingewikkeld voor simpele toepassingen), en met alle beschikbare tools ontwikkelt het uiteindelijke vele malen makkelijker dan een REST API. Zelf ben ik een voorstander van self-documenting code en het liefst zo weinig mogelijk documentatie om iets duidelijk te maken. Met Swagger/OpenAPI was het een heel gedoe om het te integreren, met GraphQL gaat dat vanzelf.

Als de bank of pensioenfonds wil dat Jan Janssen in de browser hun API kan gebruiken, zou ik zeggen, gebruik een REST API met OpenAPI. Echter, wil je het goed en veilig aanbieden dan is er een frontend nodig en in dat geval is het ecosysteem van GraphQL misschien wel makkelijker om te gebruiken.

Een interessante video m.b.t. API design:
GraphQL, gRPC or REST? Resolving the API Developer's Dilemma - Rob Crowley
Ja, momenteel hebben we een REST API met OpenAPI. Ik vroeg mij af of het de moeite waard is om ook de GraphQL endpoints beschikbaar te maken :)
Hiervoor is het misschien interessant om te kijken naar Vulcain (https://github.com/dunglas/vulcain). Dit maakt een GraphQL-achtige manier van communiceren mogelijk voor je REST-API. Je kunt zelfs de GraphQL query language gebruiken als je dat wilt (https://github.com/dungla...uery-language-for-vulcain)
Hiervoor is het misschien interessant om te kijken naar Vulcain (...)
Jammer van de maffe licensering van dat progsel:
License and Copyright

tl;dr:

proprietary software can implement the Vulcain specification
proprietary software can be used behind the Vulcain Gateway Server without having to share their sources
modifications made to the Vulcain Gateway Server must be shared
alternatively, a commercial license is available for the Vulcain Gateway Server

The specification is available under the IETF copyright policy. The Vulcain specification can be implemented by any software, including proprietary software.

The Vulcain Gateway Server is licensed under AGPL-3.0. This license implies that if you modify the Vulcain Gateway Server, you must share those modifications. However, the AGPL-3.0 license applies only to the gateway server itself, not to software used behind the gateway.

For companies not wanting, or not able to use AGPL-3.0 licensed software, commercial licenses are also available. Contact us for more information.

Treeware

This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.
7(8)7

[Reactie gewijzigd door RoestVrijStaal op 24 juli 2024 04:45]

Zelf ben ik een voorstander van self-documenting code en het liefst zo weinig mogelijk documentatie om iets duidelijk te maken. Met Swagger/OpenAPI was het een heel gedoe om het te integreren, met GraphQL gaat dat vanzelf.
Moet je HATEOAS en HAL browser eens even bekijken. Hoef je nooit meer documentatie te maken ;).
GraphQL is een end-to0end query language spec, inclusief een prachtige toolset en meer inclusief servers als Apollo of Hasura, automatische database generatoren (twee-weg, dus ook code generatie vanuit database schema), subscriptions (real-time updates adh van je query), horizontale schaalbaarheid, caching, joinen van meerdere databronnen, etc..

Ik vind het daarom totaal niet te vergelijken met ites als OpenAPI. Dat klinkt erg simpel.

Sites als die van de Telegraaf en de KLM gebruiken overigens GraphQL om de frontend en backend te koppelen, naast grote sites als GitHub en sinds kort ook Twitter...
Ja, persoonlijk (buiten werk om) groot fan van Hasura. De komende versie komt met een functie om van je GraphQL ook RESTful endpoints te maken zie: https://github.com/hasura...leases/tag/v1.4.0-alpha.1
Ik stond zelf voor de keuze GraphQL vs REST/JSON, maar heb uiteindelijk voor de 2e optie gekozen; mijn front-end is namelijk niet de enige client, ook onze klanten - die niet zo tech savvy of modern als ik zijn (ik bedoel dat onze applicatie een GUI heeft is in onze industrie blijkbaar al baanbrekend) - moeten er gebruik van maken, en gezien je REST nagenoeg overal mee kunt gebruiken leek het me makkelijker.

Ik schrijf een OpenAPI en laat de openapi-generator CLI zowel client- als server-side code genereren. Alleen models, de client / servers zelf zijn makkelijk genoeg te schrijven en de generator genereert geen implementatie-code voor me.
Ja, daar heb je een goed punt. Onze klanten kunnen ook gebruik maken van onze GraphQL API en daar loop ik toch wel tegenaan dat het als lastig ervaren wordt, want onbekend. Als ik ze dan even aan het handje hou zijn ze wel enthousiast. Maar.... dat kost me best veel werk.

Jouw oplossing klinkt ook erg goed.
Bedankt voor het statement. Ook een rede waarom?
Ik vond het ook een drama om ermee te werken.

Je maakt gebruik van een "query"-achtig taaltje dat toch weer geen SQL is. Wat een mindfuck an sich is, omdat je aan de backend-kant ook weer queries staat te schrijven 8)7
De data kreeg ik er maar niet fatsoenlijk uit getrokken.

Daarnaast zijn de foutmeldingen niet echt verbose van op welke regel de fout zit en waarom. Ik kan me nog herinneren dat ik en mijn collega een halve dag bezig waren om de fout te vinden, totdat blijkt dat er bij een naampje een hoofdletter ontbrak.

Daarna hebben we maar besloten om het lekker oldschool REST te implementeren met bewezen technologieën en het GraphQL-avontuur te laten voor wat het is.

[Reactie gewijzigd door RoestVrijStaal op 24 juli 2024 04:45]

Precies. Yet another format. Darn.
Wat een leuk artikel! Zelf een poosje geleden ook gebruikt binnen een project. Eerst de api specificeren en daarna automatisch zowel server- als clientcode genereren. Je kunt zelfs al integration tests gaan schrijven voordat je überhaupt begint met het ontwikkelen van de server.

Leuke sidenode is dat OpenAPI ook binnen overheid steeds meer lijkt te worden omarmt. Waar het eerder vaak moeilijke SOAP of zelfs custom koppelingen waren, wordt er steeds meer ontwikkeld met OpenAPI. Leuke plek om eens te kijken is in de demo van NLX, een nieuw platform om informatie uit te wisselen waarbij privacy en logging vanaf het begin zijn meegenomen in het ontwerp: https://directory.demo.nlx.io/
Ahem, OpenAPI (voorheen swagger) heeft juist 1 van de sterke punten overgenomen van SOAP: de documentatie. De WSDL (de specificatie) is zelfs verplicht.
De OpenAPI Specification is sinds 2018 al een standaard voor de overheid, zie het forumstandaardisatie: https://www.forumstandaar...den/openapi-specification. Dus ja het wordt gebruikt en ja het kan beter ingericht worden, want nog niet overal is het volledig goed geïmplementeerd.
Ja graag gedaan ;). Het team waar ik in gewerkt heb heeft daar hard voor gepushed. Ook de Nederlandse api strategie en de DSO api strategie heb ik aan mee mogen werken. Vooral implementatie kant van het verhaal.

De NL api en URL strategie zijn gebaseerd op die van het DSO. Erg fijn om mee te werken.
Ik gebruik dit ook al langere tijd, in een design-first methode. OpenAPI documentatie opstellen, delen met de klant/gebruiker en bespreken. Vervolgens kun je op basis daarvan beginnen te ontwikkelen, of je API gateway opbouwen. Bijvoorbeeld Azure API Management 'slikt' OpenAPI specificaties, maakt een mooie developerportal met documentatie en kan direct een mocking server voor je opzetten. Ideaal.

Voor Python/Flask developers - kijk ook eens naar Connexion (https://github.com/zalando/connexion). Handled op basis van je OpenAPI spec de routing en de validatie, biedt een endpoint met swaggerUI voor documentatie en verzorgt eventueel ook authenticatie voor je. Ik heb op die manier regelmatig binnen een paar uur een werkende, vrijwel productie-ready API opgezet.

[Reactie gewijzigd door dlatch op 24 juli 2024 04:45]

Ik weet dat ik vaak geklaagd heb over de kwaliteit van de 'premium' artikelen, maar dit is er 1 die ik wel de naam premium waard vind. Het is iets dat ik in bijvoorbeeld een betaald tijdschrift verwacht tegen te komen.
Hulde!
Stukje over documentatie is wel grappig om te lezen. Is altijd een bijzonder discussiepunt. In mijn ervaring is het in 99% van de gevallen achterhaald, onvolledig, onduidelijk of een combinatie van de drie. Belangrijkste vraagstuk wat 9 van de 10 keer wordt overgeslagen is de doelgroep; voor wie is het? Boekwerken aan documentatie en testrapporten gezien die leesbaar moesten zijn voor de business, maar waar niemand in geintresseerd was buiten de ontwikkelaars.
Documentation as Code heeft altijd de voorkeur. En wanneer je communiceert met een collega ontwikkelaar heb je echt geen documentatie nodig. Makkelijkste is om stukjes code delen waar al dan niet commentaar in is verwerkt. Of nog makkelijker; implementatie voorbeelden.

En wat betreft de kosten van reparatie: de truuk is om binnen 5 minuten live te staan op productie waardoor de reparatiekosten laag zijn. In zo'n situatie is het updaten van documentatie al snel een bottle neck...
Dit is op te lossen middels contract testing. Je draait dan geautomatiseerde tests om de responses te vergelijken met de specificatie. Als de response niet matcht met de specificatie faalt de test. Als je dit onderdeel maakt van je continuous integration voorkom je dat de documentatie achter komt te lopen.

Contract tests voorkomen dat je in eerste instantie andere responses genereert dan je gespecificeerd hebt. Dat zorgt er in theorie voor dat je minder kosten kwijt zou zijn aan reparaties waarin de documentatie of de code aangepast moet worden.
Ik ben bekend met contract testing, maar begrijp niet exact wat je bedoelt. Is het contract gekoppeld aan je documentatie, zodat je automatisch gegenereerde docs hebt?
Wat je zegt is ongeveer waar. Het OpenAPI document is eigenlijk het contract geworden. Met dit contract kun je verifiëren of je responses overeenkomen met hoe ze gespecificeerd zijn. Op basis van dit contract genereer je ook je automatisch documentatie.

Wanneer je een verandering doorvoert in één van je responses moet je die wijziging ook vastleggen in je OpenAPI document omdat anders je contract test faalt. Zolang dit onderdeel is van je CI/CD proces dwing je af dat je API alleen responses kan teruggeven zoals die gespecificeerd zijn.
Mijn persoonlijke 'favoriet': Documentatie waar je letterlijk niets aan hebt.

"Add user: Use this to add a user<EOF>"... Ja dank je, zo ver was ik ook al. Wil je een UPN? E-mailadres? sAMAccountName? Met of zonder domein?

Als ontwikkelaar (meer Ops dan Dev, maar goed :P ) ben ik inderdaad wel blij als ik de code kan zien; heb je vaak veel meer aan dan aan wat er voor documentatie door moet gaan. En aangezien hetgeen ik moet gebruiken zelden van onszelf is, is het vaak lastig om betere documentatie (in welke vorm dan ook) te krijgen.
Dit is één van de belangrijkste voordelen van de OpenAPI specificatie. Met een OpenAPI document heb je de mogelijkheid om zowel je request als je responses te beschrijven. Je legt daarin vast welke velden verplicht zijn, welke optioneel zijn en hoe de data-structuur eruit moet zien.

Je voorbeeld is overigens treffend. Vaak zijn de makers van documentatie veel te summier in het documenteren van een API. Het gebruik van specifiek vakjargon is een ander punt van frustratie waar ik me vaak aan erger wanneer ik andermans API documentatie lees.

Als je het mij vraagt wordt de kwaliteit van documentatie bepaald door de gebruikers. Daarom laat ik de documentatie die ik schrijf altijd controleren door anderen die geen onderdeel uitmaken van het team dat de API gebouwd heeft.
Waarom niet gewoon weer lekker SOAP gebruiken? Werkt veel beter dan al die vage REST API's imho. Je weet precies waar je aan toe bent, welke velden je wel of niet terug kunt krijgen, wat wel of niet nullable kan zijn. Met een strong typed taal heb je meteen classes die je niet meer zelf hoeft te coden, je hebt geen last van de tig verschillende REST-manieren om iets te doen.
Leuk als je Java of .NET programmeur bent, maar probeer maar eens een volledige SOAP toolkit (vergelijkbaar met bv. Apache CXF) in PHP, Javascript, Go of op iOS of Android te vinden. De support in de meeste talen is vrij beperkt.
Daarnaast is SOAP ook een draak: XML is zowel voor mensen als machines lastig te lezen en de input van diverse commissies die 15 jaar terug alle wielen opnieuw aan het uitvinden waren in de vorm van WS-* specificaties kunnen we IMO maar beter snel vergeten...
Alles wat je noemt is ook heel prima voor elkaar te krijgen met REST API's.

Bijvoorbeeld in .NET gebruikte ik rond 2018 de combinatie van Swagger + FluentValidation. Deed een code first approach, en had een stukje code draaien die de validatie regels gedefinieerd met FluentValidation koppelde aan Swagger. Swagger maakte er een mooie OpenAPI specificatie van inclusief alle validatie regels.

Op basis van die OpenAPI specificatie kon ik direct client code generen, want die functionaliteit zat al ingebakken in Visual Studio destijds.
En zo is het verhaal weer rond. We gingen weg van XML met de XSD en WSDL, omdat je zoveel moest beschrijven voor dat je service kunt aanbieden. Alle aspecten komen nu weer aanbod, maar dan in een ander jasje met JSON. En dingen als versies, backward compatibiliteit etc. komen ook nog wel aan de beurt.
GraphQL is natuurlijk niet hetzelfde als een API. Dat zou hetzelfde zijn als te stellen dat je SQL client je database is of je browser het internet.
SOAP was een draak omdat het te veel gelegenheid biedt om te cheaten. Ik heb met redeijk wat SOAP API's gewerkt (en doe datn nog steeds) en vrijwel allemaal nemen ze bizarre shortcuts. Custom, XML-escaped XML in de payload van de soap body, of zelfs JSON in de SOAP body, XSD's met gedupliceerde types in verschillende messages in dezelfde namespace, niet allen met dezelfde definitie, afwisseling tussen enums as string of als echte enum, inconsistente datum-notaties en wat al niet meer. Of een WSDL-spec die alleen een generieke Any-payload toestaat en dus het genereren van de code niet faciliteert.

REST is gewoon een stuk laagdrempeliger en eenvoudiger protocol,en je kunt er een hoop minder mee verklooien. Voor een bestaande API kan je prima een OpenAPI-spec maken. Daarnaast is JSON een stuk beter leesbaar door mensen dus het is op alle fronten veel werkbaarder.
Ik geef je gelijk op al je ervaringen met XML. Ik zeg alleen dat dit zich weer gaat herhalen nu er een specificatie boven op JSON komt.
Natuurlijk is JSON op alle fronten veel werkbaarder. Dat is de reden waarom het een vogelvlucht heeft genomen. Al ervaringen met XML ga je met OpenAPI ook weer krijgen.
Leuk artikel, maar hier zijn van veel onderstellingen uitgegaan.

Curl op windows is zeer omslachtig, tenzij je een ubuntu shell ofzo gebruik. Je kan uiteraard altijd wel postman gebruiken. Is ook iets "vriendelijker" in gebruik. Want velen werken nu eenmaal niet graag met een commandline

Mij maakt het allemaal niet uit, mijn eerste linux ervaring was redhat 5 of 6 ofzo jaren 96-91, toen moest ik nog x windows configureren en 3de muisknop etc. Maar niet iedereen gebruikt een linux (of mac machine) en velen kenden het Linux subsystem onder Windows niet. Het werkt, ik maak er ook gebruik van, wanneer ik verplicht ben om in een Windows omgeving te werken. Gewoon omdat het sommige dingen toch echt wel gemakkelijker maakt (voor mij toch). Enja curl zou ook op powershell werken blijkbaar, maar nooit getest
Zou het helpen als ik zou toevoegen aan het artikel dat je het OpenAPI document rechtstreeks kan importeren in Postman om zo je requests te maken?

Ik wou zo veel mogelijk wegblijven van extra third-party tools om niet alles nog complexer te maken, maar ik kan me voorstellen dat niet iedereen even goed overweg kan met de command-line.
Ben zelf nog op zoek naar een visuele editor om openapi specs te schrijven. In de teksteditor wordt het snel onoverzichtelijk
Kijk naar Stoplight Studio. De gratis versie biedt genoeg mogelijkheden om je specs te schrijven in een mooie editor.

https://stoplight.io/studio/
Wij hebben sinds 2 weken onze migratie doorlopen om van https://next.stoplight.io/ (swagger) naar https://stoplight.io/studio/ (open api) te moven.

next.stoplight.io is hun vorig product, maar daar is alle development gestopt en hun volledige development team zit nu op stoplight studio te werken.

Leuke aan dit soort tools is dat je componenten kan define die je dan over meerdere requests kan gebruiken, b.v. een header die op elke request toegevoegd moet worden. Indien deze dan wijzigt moet je enkel dat component aanpassen en overal is de documentatie meteen geupdate.

Small side note: je merkt in praktijk dat deze tool nog vol in ontwikkeling is. Soms zijn er dingen die je in de code view kan aanpassen omdat de editor hier nog niet mee overweg kan.

edit: typo

[Reactie gewijzigd door BabaYagaBE op 24 juli 2024 04:45]

Je zou eens kunnen kijken naar Apicurio Studio, dit is open source.
Er is een online variant om het editten eens te ervaren: Apicurito, nog wel even op het knopje 'Try Live' drukken.

Zie ook mijn eerdere reactie: M.o.P. in 'reviews: De OpenAPI-standaard - Api's gebruiken met minimale inspa...
Ik zou een paar clients noemen; Postman is een bekende, maar behoorlijk locked-in (je kunt niet zomaar een file met API calls delen in je bedrijf, ze pushen je naar een team abonement). Insomnia is een andere, ben vergeten hoe en wat.

Zelf zet ik de Swagger UI in mijn project, die genereert een webpagina dat zowel documentatie toont als een API client implementeert. Het is niet de mooiste trouwens, het maken van requests is wat omslachtig en bijv. de models worden best lelijk weergegeven, maar het werkt prima.

De Swagger Editor (https://swagger.io/tools/swagger-editor/) staat daar naast, die laat een live preview zien van hetgene je in Swagger UI laat zien en laat je de spec editen.
Een groot voordeel van OpenAPI is juist dat tools dit automatisch kunnen gebruiken om je handmatig werk uit handen te nemen, dus vind ik de command-line juist niet zo'n goede keuze.

Het filmpje dat hier staat toont bijvoorbeeld goed hoe je na het importeren van een OpenAPI specificatie je hele API beschikbaar is in Postman, inclusief alle velden die je kunt gebruiken, met de types van de velden en een omschrijving (al is de omschrijving leeg in het filmpje, wat dan weer jammer is):

https://learning.postman....ons/working-with-openAPI/
Het zal je verbazen hoe weinig het gebruik van een CLI voorkomt. Het zijn vaak de kleine groep diehard gebruikers die alles met de CLI doen en dat overal willen verkondigen, maar de meeste ontwikkelaars die ik ken en heb gesproken kiezen gewoon voor een simpele "import" knop in postman als dat kan in plaats van aan de slag te gaan met de CLI, Linux en weet ik veel wat
Er zijn genoeg programmeurs mensen en programmeurs die met moeite met een commandline overweg kunnen, daar zou je je echt van kunnen verschieten hoor. Dat is voor velen een horror verhaal. Ik heb een jaar of 2 geleden nog een paar stagiars en pas afgestudeerden gehad, en die konden met moeite iets gedaan krijgen op een commandline. Ze kenden sommige commando's en daar stopte het.

Voor mij hoeft die verwijziging naar postman niet hoor, maar dat is iets waar de meeste wel mee overweg kunnen en maakt het iets gemakkelijker en toegankelijker. Ik ben nu ook niet de grootste fan van thirdparty tools, maar postman is toch wel algemeen aanvaard als een goeie tool (bij mijn weten). En dit kan de drempel toch verlagen. Curl bestaat al zolang, maar zelf durf ik ook nog wel eens een typfout maken ofzo, en als je dan al niet gewend ben aan een commandline, dan kan postman toch wel een meerwaarde zijn denk ik
Curl op windows is zeer omslachtig, tenzij je een ubuntu shell ofzo gebruik. Je kan uiteraard altijd wel postman gebruiken. Is ook iets "vriendelijker" in gebruik. Want velen werken nu eenmaal niet graag met een commandline
Powershell werkt prima, Invoke-WebRequest en Invoke-RestMethod
Ik lees verschillende dingen. Enerzijds haakt het in op hoe je het snelst feedback vergaart (design first/code first) - wat altijd in tandem is overigens (want ook design-first kan heel kostbaar zijn door dingen te verlangen van code die niet zo 1 2 3 te fabrieken zijn). Anderzijds lees ik een standaard om API's te beschrijven voor REST apis.

Dat laatste vind ik grappig, want we zijn zo echt full-circle gegaan vanuit de wereld van XML/XSD en WSDLS. Ook dat is bedacht met standaard in gedachte, documentatie genereren (en code zelfs). Alleen de manier van opschrijven (XML ipv JSON) is anders.
Haha herkenbaar, meest frustrerend is nog de REST profeten die vervolgens wel systeemfuncties in de architectuur proberen te proppen.
Je bedoelt RPC-achtige zaken als bijv. "POST /activate"? Ik denk dat je daar uiteindelijk niet omheen komt.

Is trouwens ook niet erg; REST is niet een harde standaard, en uitzonderingen voor dit soort use cases zijn best normaal. Ik zou REST niet als een harde standaard beschouwen.
Jep, IMO ook geen probleem. Ik moet alleen altijd lachen als deze personen REST juist wel vertaald hebben naar harde (architectuur)eisen.
Eens, dat purisme levert meer problemen op dan het oplost 8)7
Dat laatste vind ik grappig, want we zijn zo echt full-circle gegaan vanuit de wereld van XML/XSD en WSDLS.
Nou precies!! 8)7
En gelukkig zonder alle XML matigheid ;)
Ik gebruik de Nswag toolchain om zaken voor OpenAPI (zowel server als client side) te genereren in .NET.

https://github.com/RicoSuter/NSwag
in de .NET wereld zijn eigenlijk 2 grote spelers om dit te genereren voor je. NSwag en Swashbuckle.

Gebruikte zelf al jaren Swashbuckle maar zie dat NSwag wat meer in opkomst is omdat die ook typescript kan genereren. Beide zijn gewoon prima opties. hier wat docs over beide: https://docs.microsoft.co...agger?view=aspnetcore-5.0
Dit heb ik ook met veel plezier gebruikt om m'n OpenAPI beschrijving plus bijbehorende TypeScript client code te genereren (Angular).
Inmiddels gebruik ik allerlei andere talen (Java, Kotlin, Python) en Vue als front-end. Iets vergelijkbaars heb ik nog niet gevonden, al heb ik ook niet heel goed gezocht. Kent iemand vergelijkbaar goede oplossing geschikt voor andere talen?
Yus: de OpenAPI Generator is volgens mij de de facto standaard code generator. Bovenin de readme hebben ze een lijst van server (stubs) en clients die ze kunnen genereren.

Ik gebruik deze zelf om Go models server-side en Typescript models client-side te genereren. Alleen models, om tijdens het ontwikkelen de server stubs of clients te genereren is een beetje stom.
Moustache template engine is wat beperkt. Verder type: string, format: uuid. Geeft ook beetje vreemde code in the Typescript clients. Niet helemaal duidelijk waarom je voor een string aan de gang moet met new Blob() en JSON stringing/parse

[Reactie gewijzigd door alienfruit op 24 juli 2024 04:45]

Heb je naar openapi-generator gekeken? Net deze week bezig geweest om de TypeScript Moustache (waardeloos trouwens) template aan te passen: https://openapi-generator.tech.

Het project is zelf in Java en Kotlin gebouwd en naast die blijkt ook Python te ondersteunen: https://openapi-generator.tech/docs/generators

[Reactie gewijzigd door alienfruit op 24 juli 2024 04:45]

Ik heb er kort naar gekeken , maar met Nswag kan ik mijn API beschrijving hosten op bijv /swagger EN ik kan met nswag clients genereren voor mijn C# en TS projecten. Als ik zo openapi generator tech gebruik zie ik dat dat een los programma is die dus die clients genereert.

Ik zou dus die tool kunnen gebruiken, maar wat voor voordelen bied dat nog meer? Met Nswag en een nswag.json waarin ik al mijn instellingen instel ben ik super flexibel.
Grootste pluspunt is dat ik er Go, Swift clients mee kan generen, verder is er niet zoveel anders. Ik heb eigenlijk alleen maar gewerkt met de CLI van beide tools.
Kan ik je vragen hoe je dat uiteindelijk gedaan hebt met de angular lib?

Ik heb ook met nswag een angular api client gemaakt, maar angular werd daar niet blij van. Ik kreeg alleen maar `Uncaught Error: Uncaught (in promise): Error: Angular JIT compilation failed: '@angular/compiler' not loaded!` errors tijdens het gebruik ervan.

Uiteindelijk heb ik het weten te fixen door er een dedicated angular lib van te maken: https://angular.io/guide/creating-libraries maar het liefste had ik natuurlijk gewoon 1 .ts bestandje die ik in een private npm package kan stoppen.

Ik ben benieuwd of je wilt delen hoe jouw uiteindelijke package eruit ziet!

Op dit item kan niet meer gereageerd worden.