Leer hoe je OpenAPI genereert uit bedoeld gedrag met Claude Code, het vergelijkt met je API-implementatie en eenvoudige client- en server-validatievoorbeelden maakt.

Een OpenAPI-contract is een gedeelde beschrijving van je API: welke endpoints er zijn, wat je stuurt, wat je terugkrijgt en hoe fouten eruitzien. Het is de afspraak tussen de server en alles wat hem aanroept (een webapp, mobiele app of een andere service).
Het probleem is drift. De draaiende API verandert, maar de spec niet. Of de spec wordt "opgeruimd" om er mooier uit te zien dan de realiteit, terwijl de implementatie vreemde velden blijft teruggeven, statuscodes mist of inconsistente error-shapes heeft. Na verloop van tijd vertrouwen mensen het OpenAPI-bestand niet meer, en wordt het gewoon een document dat iedereen negeert.
Drift ontstaat meestal door normale druk: een snelle fix wordt uitgerold zonder de spec bij te werken, een nieuw optioneel veld wordt "tijdelijk" toegevoegd, paginatie evolueert, of teams updaten verschillende "sources of truth" (backendcode, een Postman-collectie en een OpenAPI-file).
Eerlijk houden betekent dat de spec overeenkomt met het echte gedrag. Als de API soms 409 teruggeeft voor een conflict, hoort dat in het contract. Als een veld nullable is, zeg het. Als auth vereist is, maak het niet vaag.
Een goede workflow levert op:
Dat laatste punt is belangrijk omdat een contract alleen helpt als het wordt afgedwongen. Een eerlijke spec plus herhaalbare checks verandert "API-documentatie" in iets waarop teams kunnen rekenen.
Als je begint met code lezen of routes kopiëren, zal je OpenAPI beschrijven wat er vandaag bestaat, inclusief eigenaardigheden die je misschien niet wilt beloven. Beschrijf in plaats daarvan wat de API voor een caller zou moeten doen en gebruik de spec om te verifiëren dat de implementatie overeenkomt.
Voordat je YAML of JSON schrijft, verzamel je per endpoint een klein aantal feiten:
Schrijf daarna gedrag als voorbeelden. Voorbeelden dwingen je specifiek te zijn en maken het makkelijker om een consistent contract op te stellen.
Voor een Tasks-API kan een happy-path voorbeeld zijn: “Maak een taak met title en krijg id, title, status en createdAt terug.” Voeg veelvoorkomende fouten toe: “Ontbrekende title geeft 400 met {\"error\":\"title is required\"}” en “Geen auth geeft 401.” Als je al edge cases kent, neem die op: of dubbele titels zijn toegestaan, en wat er gebeurt als een taak-ID niet bestaat.
Vang regels op als simpele zinnen die niet van code-details afhankelijk zijn:
title is vereist en 1-120 tekens.”limit is ingesteld (max 200).”dueDate is ISO 8601 date-time.”Bepaal tenslotte je v1-scope. Als je het niet zeker weet, houd v1 klein en duidelijk (create, read, list, update status). Bewaar search, bulk-updates en complexe filters voor later zodat het contract geloofwaardig blijft.
Voordat je Claude Code vraagt een spec te schrijven, noteer gedragsnotities in een klein, herhaalbaar formaat. Het doel is het moeilijk te maken per ongeluk gaten op te vullen met gissingen.
Een goede template is kort genoeg om daadwerkelijk te gebruiken, maar consistent genoeg dat twee mensen hetzelfde endpoint op vergelijkbare wijze zouden beschrijven. Richt je op wat de API doet, niet hoe hij is geïmplementeerd.
Gebruik één blok per endpoint:
METHOD + PATH:
Purpose (1 sentence):
Auth:
Request:
- Query:
- Headers:
- Body example (JSON):
Responses:
- 200 OK example (JSON):
- 4xx example (status + JSON):
Edge cases:
Data types (human terms):
Schrijf minstens één concreet request en twee responses. Voeg statuscodes en realistische JSON-bodies met echte veldnamen toe. Als een veld optioneel is, laat in één voorbeeld zien dat het ontbreekt.
Benadruk edge cases expliciet. Dit zijn de plekken waar specs later stilletjes onwaar worden omdat iedereen iets anders dacht: lege resultaten, ongeldige IDs (400 vs 404), duplicaten (409 vs idempotent gedrag), validatiefouten en paginatie-limieten.
Noteer ook datatypes in gewone woorden voordat je aan schema's denkt: strings vs numbers, date-time formats, booleans en enums (lijst toegestane waarden). Dit voorkomt een "mooie" schema die niet overeenkomt met echte payloads.
Claude Code werkt het beste als je het als een zorgvuldige schrijver behandelt. Geef je gedragsnotities en strikte regels voor hoe de OpenAPI eruit moet zien. Als je alleen zegt “schrijf een OpenAPI spec”, krijg je meestal gissingen, inconsistente naamgeving en ontbrekende error-cases.
Plak eerst je gedragsnotities, en voeg dan een strakke instructieblok toe. Een praktisch promptvoorbeeld ziet er zo uit:
You are generating an OpenAPI 3.1 YAML spec.
Source of truth: the behavior notes below. Do not invent endpoints or fields.
If anything is unclear, list it under ASSUMPTIONS and leave TODO markers in the spec.
Requirements:
- Include: info, servers (placeholder), tags, paths, components/schemas, components/securitySchemes.
- For each operation: operationId, tags, summary, description, parameters, requestBody (when needed), responses.
- Model errors consistently with a reusable Error schema and reference it in 4xx/5xx responses.
- Keep naming consistent: PascalCase schema names, lowerCamelCase fields, stable operationId pattern.
Behavior notes:
[PASTE YOUR NOTES HERE]
Output only the OpenAPI YAML, then a short ASSUMPTIONS list.
Als je de draft krijgt, scan dan eerst de ASSUMPTIONS. Dáár wordt eerlijkheid gewonnen of verloren. Keur goed wat juist is, corrigeer wat niet klopt en draai opnieuw met bijgewerkte notities.
Om naamgeving consistent te houden, geef conventies vroeg aan en houd je eraan. Bijvoorbeeld: een stabiel operationId-patroon, tags met alleen zelfstandige naamwoorden, enkelvoudige schema-namen, één gedeeld Error-schema en één auth-scheme-naam die overal wordt gebruikt.
Als je in een vibe-coding workspace zoals Koder.ai werkt, helpt het om de YAML vroeg als een echt bestand op te slaan en in kleine diffs te itereren. Zo zie je welke wijzigingen voortkomen uit goedgekeurde gedragsbeslissingen versus details die het model gokte.
Voordat je iets met productie vergelijkt, zorg dat het OpenAPI-bestand intern consistent is. Dit is de snelste plek om wishful thinking en vage bewoordingen te vinden.
Lees elk endpoint alsof je de client-developer bent. Richt je op wat een caller moet sturen en waarop ze kunnen rekenen om terug te krijgen.
Een praktische review-pass:
Foutresponses verdienen extra aandacht. Kies één gedeelde vorm en hergebruik die overal. Sommige teams houden het heel simpel ({ error: string }), anderen gebruiken een object ({ error: { code, message, details } }). Beide kunnen werken, maar mix ze niet door elkaar. Als je dat doet, groeit clientcode vol speciale gevallen.
Een snelle sanity-scenario helpt. Als POST /tasks title vereist, dan moet het schema dat verplicht markeren, de failure-response laten zien welke error-body je eigenlijk teruggeeft en moet de operatie duidelijk maken of auth vereist is.
Zodra de spec leest als bedoeld gedrag, behandel de draaiende API als de waarheid voor wat clients vandaag ervaren. Het doel is niet om te "winnen" tussen spec en code. Het doel is verschillen vroeg bloot te leggen en een duidelijke beslissing te nemen over elk verschil.
Voor een eerste ronde zijn echte request/response-samples meestal de eenvoudigste optie. Logs en geautomatiseerde tests werken ook als ze betrouwbaar zijn.
Let op veelvoorkomende mismatches: endpoints die in de ene bron bestaan maar niet in de andere, verschil in veldnaam of -vorm, statuscodeverschillen (200 vs 201, 400 vs 422), ongedocumenteerd gedrag (paginatie, sortering, filtering) en auth-verschillen (spec zegt publiek, code vereist een token).
Voorbeeld: je OpenAPI zegt dat POST /tasks 201 retourneert met {id,title}. Je roept de draaiende API aan en krijgt 200 plus {id,title,createdAt}. Dat is niet "ongeveer hetzelfde" als je client-SDKs van de spec genereert.
Voordat je iets wijzigt, beslis hoe je conflicten oplost:
Houd elke wijziging klein en reviewbaar: één endpoint, één response, één schema-aanpassing. Dan is het makkelijker te reviewen en opnieuw te testen.
Als je eenmaal een spec hebt die je vertrouwt, zet die om in kleine validatievoorbeelden. Dit is wat drift uit de deur houdt.
Op de server betekent validatie dat je snel faalt wanneer een request niet aan het contract voldoet, en een duidelijke fout teruggeeft. Dat beschermt je data en maakt bugs makkelijker te vinden.
Een eenvoudige manier om server-validatievoorbeelden uit te drukken is ze als cases te schrijven met drie delen: input, verwachte output en verwachte fout (een foutcode of message-patroon, geen exacte tekst).
Voorbeeld (contract zegt dat title vereist is en 1 tot 120 tekens):
{
"name": "Create task without title returns 400",
"request": {"method": "POST", "path": "/tasks", "body": {"title": ""}},
"expect": {"status": 400, "body": {"error": {"code": "VALIDATION_ERROR"}}}
}
Op de client draait validatie om het detecteren van drift voordat gebruikers het merken. Als de server een andere vorm begint terug te geven, of een verplicht veld verdwijnt, moeten je tests dit signaleren.
Houd clientchecks gericht op waar je echt op vertrouwt, zoals “een taak heeft id, title, status.” Vermijd het afdwingen van elk optioneel veld of exacte volgorde. Je wilt failures bij breaking changes, niet bij onschuldige toevoegingen.
Een paar richtlijnen die tests leesbaar houden:
Als je met Koder.ai werkt, kun je deze voorbeeldcases naast je OpenAPI-file genereren en bijhouden, en ze bijwerken als onderdeel van dezelfde review wanneer gedrag verandert.
Stel je een kleine API voor met drie endpoints: POST /tasks maakt een taak, GET /tasks lijst taken en GET /tasks/{id} retourneert één taak.
Begin met het schrijven van een paar concrete voorbeelden voor één endpoint, alsof je het aan een tester uitlegt.
Voor POST /tasks kan het bedoelde gedrag zijn:
{ "title": "Buy milk" } en krijg 201 met een nieuw taakobject, inclusief een id, de title en done:false.{} en krijg 400 met een error zoals { "error": "title is required" }.{ "title": "x" } (te kort) en krijg 422 met { "error": "title must be at least 3 characters" }.Wanneer Claude Code de OpenAPI opstelt, moet het snippet voor dit endpoint het schema, statuscodes en realistische voorbeelden bevatten:
paths:
/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
examples:
ok:
value: { "title": "Buy milk" }
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
examples:
created:
value: { "id": "t_123", "title": "Buy milk", "done": false }
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
missingTitle:
value: { "error": "title is required" }
'422':
description: Unprocessable Entity
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
tooShort:
value: { "error": "title must be at least 3 characters" }
Een veelvoorkomende mismatch is subtiel: de draaiende API geeft 200 in plaats van 201, of geeft { "taskId": 123 } terug in plaats van { "id": "t_123" }. Dat soort "bijna hetzelfde" breekt gegenereerde clients.
Los het op door één waarheid te kiezen. Als het bedoelde gedrag klopt, pas dan de implementatie aan om 201 en de afgesproken Task-vorm te retourneren. Als productiede gedrag al wordt vertrouwd, update dan de spec (en de behavior notes) om de realiteit weer te geven en voeg de ontbrekende validatie- en errorresponses toe zodat clients niet verrast worden.
Een contract wordt oneerlijk wanneer het stopt met het beschrijven van regels en in plaats daarvan beschrijft wat je API op een goede dag teruggaf. Een simpele test: kan een nieuwe implementatie aan deze spec voldoen zonder de eigenaardigheden van vandaag te kopiëren?
Een valkuil is overfitting. Je legt één response vast en maakt er wet van. Voorbeeld: je API geeft op dit moment dueDate: null voor elke taak, dus de spec zegt dat het veld altijd nullable is. Maar de echte regel kan zijn “vereist wanneer status scheduled is.” Het contract moet de regel uitdrukken, niet alleen de huidige dataset.
Fouten zijn waar eerlijkheid vaak faalt. Het is verleidelijk alleen succesresponses te spec'en omdat die er netjes uitzien. Maar clients hebben de basics nodig: 401 als token ontbreekt, 403 voor forbidden access, 404 voor onbekende IDs en een consistente validatiefout (400 of 422).
Andere patronen die problemen veroorzaken:
taskId in één route en id elders, of priority als string in één response en number in een andere).string, alles optioneel).Een goed contract is testbaar. Als je geen falende test uit de spec kunt schrijven, is het nog niet eerlijk genoeg.
Voordat je een OpenAPI-file aan een andere team geeft (of in docs plakt), doe een snelle ronde: "kan iemand dit gebruiken zonder in je hoofd te kruipen?"
Begin met voorbeelden. Een spec kan geldig zijn en toch nutteloos als elk request en response abstract is. Voor elke operatie, voeg minstens één realistisch request-voorbeeld en één succesresponse-voorbeeld toe. Voor fouten is één voorbeeld per veelvoorkomend falen (auth, validatie) meestal genoeg.
Controleer daarna consistentie. Als het ene endpoint { "error": "..." } teruggeeft en een ander { "message": "..." }, moet clientcode branching logic bevatten. Kies één error-vorm en hergebruik die, samen met voorspelbare statuscodes.
Een korte checklist:
Een praktisch trucje: kies één endpoint, doe alsof je de API nog nooit gezien hebt, en beantwoord: "Wat stuur ik, wat krijg ik terug, en wat kan breken?" Als de OpenAPI dat niet duidelijk kan beantwoorden, is hij nog niet klaar.
Deze workflow betaalt zich uit als hij regelmatig draait, niet alleen tijdens releases. Kies een eenvoudige regel en houd je eraan: voer hem uit wanneer een endpoint verandert en nogmaals voordat je een bijgewerkte spec publiceert.
Houd eigenaarschap simpel. Degene die een endpoint verandert, werkt de behavior notes en spec-draft bij. Een tweede persoon reviewt de "spec vs implementatie" diff zoals een code review. QA- of support-collega's zijn vaak uitstekende reviewers omdat zij onduidelijke responses en edge cases snel opmerken.
Behandel contractwijzigingen als code-wijzigingen. Als je een chat-gestuurde builder zoals Koder.ai gebruikt, maak dan een snapshot voordat je risicovolle edits doet en gebruik rollback als dat nodig is. Koder.ai ondersteunt ook het exporteren van broncode, wat het makkelijker maakt om spec en implementatie naast elkaar in je repo te houden.
Een routine die meestal werkt zonder teams te vertragen:
Volgende actie: kies één endpoint dat al bestaat. Schrijf 5–10 regels behavior notes (inputs, outputs, error-cases), genereer een draft OpenAPI uit die notities, valideer hem, en vergelijk hem dan met de draaiende implementatie. Repareer één mismatch, retest en herhaal. Na één endpoint blijft de gewoonte vaak plakken.
OpenAPI-drift betekent dat de API die je draait niet meer overeenkomt met het OpenAPI-bestand dat je deelt. De spec kan nieuwe velden, statuscodes of auth-regels missen, of het kan "ideaal" gedrag beschrijven dat de server in werkelijkheid niet volgt.
Het is belangrijk omdat clients (apps, andere services, gegenereerde SDK's, tests) beslissingen baseren op het contract, niet op wat je server "gewoonlijk" doet.
Drift veroorzaakt willekeurige en moeilijk te debuggen client-fouten: een mobiele app verwacht 201 maar krijgt 200, een SDK kan een response niet deserializen omdat een veld is hernoemd, of error-afhandeling faalt omdat error-shapes verschillen.
Zelfs als niets crasht, verliezen teams vertrouwen en stoppen ze met het gebruiken van de spec, waardoor je vroege waarschuwingssysteem verdwijnt.
Omdat code het huidige gedrag weerspiegelt, inclusief toevallige eigenaardigheden die je misschien niet voor lange termijn wilt beloven.
Een betere aanpak: beschrijf eerst het bedoelde gedrag (inputs, outputs, errors) en verifieer dan dat de implementatie ermee overeenkomt. Zo krijg je een contract dat je kunt afdwingen, in plaats van een momentopname van de routes van vandaag.
Per endpoint leg je vast:
Kies één foutvorm en hergebruik die overal.
Een simpele standaard is ofwel:
{ "error": "message" }, of{ "error": { "code": "...", "message": "...", "details": ... } }Maak het consistent over endpoints en voorbeelden. Consistentie is belangrijker dan verfijning, omdat clients deze vorm zullen hardcoden.
Geef Claude Code je gedragsnotities en strikte regels en zeg expliciet dat het niets mag verzinnen. Een praktische instructieset:
TODO in the spec and list it under ASSUMPTIONS.”Error) and reference them.”Na generatie, controleer eerst de . Daar begint drift als je gissingen accepteert.
Valideer de spec eerst zelf:
201)Dat vangt "wishful" OpenAPI-files voordat je naar productiegedrag kijkt.
Behandel de draaiende API als wat gebruikers vandaag ervaren en beslis per mismatch:
Houd wijzigingen klein (één endpoint of één response tegelijk) zodat je snel kunt retesten.
Server-side validatie moet binnenkomende requests die het contract overtreden snel afwijzen en een duidelijke, consistente fout teruggeven (status + error code/shape).
Client-side validatie moet breaking changes vroeg detecteren door alleen te controleren waar je echt op vertrouwt:
Vermijd het afdwingen van alle optionele velden zodat tests falen op echte brekende veranderingen, niet op onschuldige aanvullingen.
Een praktische routine is:
Als je in Koder.ai werkt kun je de OpenAPI-file naast de code houden, snapshots maken vóór risicovolle edits en terugrollen als een spec/code-wijziging rommelig wordt.
Als je een concreet request en twee responses kunt schrijven, is dat meestal genoeg om een eerlijke spec te schetsen.