Impara a generare OpenAPI dal comportamento usando Claude Code, confrontala con l'implementazione dell'API e crea esempi semplici di validazione client e server.

Un contratto OpenAPI è una descrizione condivisa della tua API: quali endpoint esistono, cosa invii, cosa ricevi in risposta e come sono gli errori. È l'accordo tra il server e chiunque lo chiami (un'app web, un'app mobile o un altro servizio).
Il problema è lo drift. L'API in esecuzione cambia, ma la spec no. Oppure la spec viene “ripulita” per apparire più bella della realtà, mentre l'implementazione continua a restituire campi strani, codici di stato mancanti o forme di errore inconsistenti. Col tempo, le persone smettono di fidarsi del file OpenAPI e diventa solo un'altra doc che tutti ignorano.
Lo drift di solito nasce da pressioni normali: una correzione veloce viene rilasciata senza aggiornare la spec, un nuovo campo opzionale viene aggiunto “temporaneamente”, la paginazione evolve o i team aggiornano diverse “sorgenti di verità” (codice backend, collection Postman e file OpenAPI).
Mantenere onesta la spec significa che la spec corrisponde al comportamento reale. Se l'API a volte restituisce 409 per un conflitto, questo appartiene al contratto. Se un campo è nullable, dillo. Se è richiesta l'autenticazione, non lasciarlo vago.
Un buon workflow ti lascia con:
Quest'ultimo punto conta perché un contratto aiuta solo quando è applicato. Una spec onesta più controlli ripetibili trasforma la “documentazione API” in qualcosa di cui i team possono fidarsi.
Se parti leggendo il codice o copiando le route, il tuo OpenAPI descriverà ciò che esiste oggi, incluse le stranezze che potresti non voler promettere. Invece, descrivi cosa dovrebbe fare l'API per un chiamante e poi usa la spec per verificare che l'implementazione corrisponda.
Prima di scrivere YAML o JSON, raccogli un piccolo set di fatti per endpoint:
Poi scrivi il comportamento come esempi. Gli esempi ti costringono a essere specifico e rendono più facile redigere un contratto coerente.
Per una Tasks API, un esempio di happy path potrebbe essere: “Crea un task con title e ricevi id, title, status e createdAt.” Aggiungi fallimenti comuni: “Title mancante restituisce 400 con {\"error\":\"title is required\"}” e “Nessuna auth restituisce 401.” Se conosci già edge case, includili: se i titoli duplicati sono permessi e cosa succede quando un ID task non esiste.
Cattura le regole con frasi semplici che non dipendano dai dettagli del codice:
title è obbligatorio e lungo 1-120 caratteri.”limit (max 200).”dueDate è ISO 8601 date-time.”Infine, decidi l'ambito della v1. Se sei incerto, mantieni la v1 piccola e chiara (create, read, list, update status). Salva ricerca, aggiornamenti bulk e filtri complessi per dopo così il contratto resta credibile.
Prima di chiedere a Claude Code di scrivere una spec, scrivi note sul comportamento in un formato piccolo e ripetibile. L'obiettivo è rendere difficile “riempire i buchi” con congetture.
Un buon template è abbastanza breve da essere effettivamente usato, ma coerente così due persone descriverebbero lo stesso endpoint in modo simile. Mantienilo focalizzato su cosa fa l'API, non su come è implementata.
Use one block 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):
Scrivi almeno una richiesta concreta e due risposte. Includi codici di stato e corpi JSON realistici con nomi di campo reali. Se un campo è opzionale, mostra un esempio in cui manca.
Indica esplicitamente gli edge case. Questi sono i punti dove le spec diventano silenziosamente false più tardi perché ognuno assume qualcosa di diverso: risultati vuoti, ID invalidi (400 vs 404), duplicati (409 vs comportamento idempotente), errori di validazione e limiti di paginazione.
Nota anche i tipi di dato in termini umani prima di pensare agli schemi: stringhe vs numeri, formati date-time, booleani ed enum (elenco valori ammessi). Questo evita uno schema “bello” che non corrisponde ai payload reali.
Claude Code funziona meglio se lo tratti come uno scriba attento. Dagli le tue note comportamentali e regole strette su come la OpenAPI deve essere strutturata. Se dici solo “scrivi una spec OpenAPI”, solitamente otterrai congetture, naming incoerente e casi di errore mancanti.
Incolla prima le note di comportamento, poi aggiungi un blocco di istruzioni rigorose. Un prompt pratico è così:
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.
Dopo aver ottenuto la bozza, controlla prima le ASSUMPTIONS. Lì si gioca l'onestà. Approva ciò che è corretto, correggi ciò che è sbagliato e rilancia con note aggiornate.
Per mantenere il naming coerente, dichiara le convenzioni all'inizio e rispettale. Per esempio: pattern stabile per operationId, nomi tag solo sostantivi, nomi di schema singolari, un Error condiviso e un solo nome per lo auth scheme usato ovunque.
Se lavori in un workspace vibe-coding come Koder.ai, aiuta salvare lo YAML come file reale presto e iterare in piccoli diff. Così vedi quali cambiamenti sono derivati da decisioni comportamentali approvate rispetto a dettagli che il modello ha indovinato.
Prima di confrontare qualsiasi cosa con la produzione, assicurati che il file OpenAPI sia internamente consistente. Questo è il luogo più veloce per intercettare desideri e linguaggio vago.
Leggi ogni endpoint come se fossi lo sviluppatore client. Concentrati su cosa il chiamante deve inviare e su cosa può aspettarsi di ricevere.
Un passaggio pratico di revisione:
Gli errori meritano attenzione extra. Scegli una shape condivisa e riutilizzala ovunque. Alcuni team la tengono molto semplice ({ error: string }), altri usano un oggetto dettagliato ({ error: { code, message, details } }). Entrambe possono funzionare, ma non mescolarle tra endpoint ed esempi. Se lo fai, il codice client accumulerà casi speciali.
Uno scenario rapido di sanity check aiuta. Se POST /tasks richiede title, lo schema dovrebbe marcarlo required, la risposta di errore dovrebbe mostrare il corpo di errore realmente restituito e l'operazione dovrebbe indicare chiaramente se l'auth è richiesta.
Una volta che la spec legge come comportamento intenzionale, tratta l'API in esecuzione come la verità di ciò che i client sperimentano oggi. Lo scopo non è “vincere” tra spec e codice, ma far emergere le differenze presto e prendere una decisione chiara su ciascuna.
Per una prima passata, campioni reali di request/response sono spesso l'opzione più semplice. Anche i log e i test automatizzati funzionano se sono affidabili.
Fai attenzione alle incongruenze comuni: endpoint presenti in un posto ma non nell'altro, differenze nei nomi o nella forma dei campi, differenze nei codici di stato (200 vs 201, 400 vs 422), comportamenti non documentati (paginazione, ordinamento, filtri) e differenze di auth (la spec dice pubblico, il codice richiede token).
Esempio: la tua OpenAPI dice che POST /tasks restituisce 201 con {id,title}. Chiami l'API in esecuzione e ottieni 200 più {id,title,createdAt}. Non è “abbastanza vicino” se generi SDK dai file spec.
Prima di modificare qualsiasi cosa, decidi come risolvere i conflitti:
Mantieni ogni cambiamento piccolo e revisionabile: un endpoint, una risposta, una modifica di schema. È più facile da revisionare e da ritestare.
Una volta che hai una spec di cui ti fidi, trasformala in piccoli esempi di validazione. Questo è ciò che impedisce al drift di tornare.
Sul server, la validazione significa fallire velocemente quando una richiesta non corrisponde al contratto e restituire un errore chiaro. Questo protegge i dati e rende i bug più facili da individuare.
Un modo semplice per esprimere esempi di validazione server è scriverli come casi con tre parti: input, output atteso ed errore atteso (un codice di errore o un pattern, non il testo esatto).
Esempio (il contratto dice che title è richiesto e deve essere 1-120 chars):
{
"name": "Create task without title returns 400",
"request": {"method": "POST", "path": "/tasks", "body": {"title": ""}},
"expect": {"status": 400, "body": {"error": {"code": "VALIDATION_ERROR"}}}
}
Sul client, la validazione serve a rilevare lo drift prima che lo vedano gli utenti. Se il server inizia a restituire una forma diversa, o un campo richiesto scompare, i tuoi test dovrebbero segnalarlo.
Mantieni i controlli client focalizzati su ciò di cui fai davvero affidamento, come “un task ha id, title, status.” Evita di asserire ogni campo opzionale o l'ordine esatto. Vuoi fallimenti su cambiamenti breaking, non su aggiunte innocue.
Alcune linee guida per mantenere i test leggibili:
Se usi Koder.ai, puoi generare e tenere questi casi esempio accanto al file OpenAPI, poi aggiornarli come parte della stessa review quando il comportamento cambia.
Immagina una piccola API con tre endpoint: POST /tasks crea un task, GET /tasks lista i task e GET /tasks/{id} restituisce un singolo task.
Inizia scrivendo alcuni esempi concreti per un endpoint, come se lo spiegassi a un tester.
Per POST /tasks, il comportamento intenzionale potrebbe essere:
{ "title": "Buy milk" } e ricevi 201 con un oggetto task nuovo, includendo id, title e done:false.{} e ricevi 400 con un errore tipo { "error": "title is required" }.{ "title": "x" } (troppo corto) e ricevi 422 con { "error": "title must be at least 3 characters" }.Quando Claude Code bozza l'OpenAPI, lo snippet per questo endpoint dovrebbe catturare schema, codici di stato ed esempi realistici:
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" }
Una discrepanza comune è sottile: l'API in esecuzione restituisce 200 invece di 201, oppure restituisce { "taskId": 123 } invece di { "id": "t_123" }. Questo tipo di differenza “quasi uguale” rompe gli SDK generati.
Risolvi scegliendo una fonte di verità. Se il comportamento intenzionale è corretto, modifica l'implementazione per restituire 201 e la forma Task concordata. Se il comportamento in produzione è già sfruttato, aggiorna la spec (e le note di comportamento) per riflettere la realtà, poi aggiungi la validazione e le risposte di errore mancanti in modo che i client non siano sorpresi.
Un contratto diventa disonesto quando smette di descrivere regole e inizia a descrivere qualunque cosa la tua API abbia restituito in un giorno fortunato. Un semplice test: una nuova implementazione potrebbe passare questa spec senza copiare le stranezze di oggi?
Un tranello è l'overfitting. Catturi una risposta e la trasformi in legge. Esempio: la tua API attualmente restituisce dueDate: null per ogni task, quindi la spec dice che il campo è sempre nullable. Ma la regola reale potrebbe essere “richiesto quando lo status è scheduled.” Il contratto dovrebbe esprimere la regola, non solo il dataset corrente.
Gli errori sono dove l'onestà spesso si rompe. È allettante specificare solo le risposte di successo perché sembrano pulite. Ma i client hanno bisogno delle basi: 401 quando manca il token, 403 per accesso vietato, 404 per ID sconosciuti e un errore di validazione coerente (400 o 422).
Altri pattern problematici:
taskId in una route ma id altrove, o priority come stringa in una risposta e numero in un'altra).string, tutto opzionale).Un buon contratto è testabile. Se non riesci a scrivere un test fallibile partendo dalla spec, non è ancora onesto.
Prima di consegnare un file OpenAPI a un altro team (o incollarlo nella docs), fai una rapida verifica “può qualcuno usare questo senza leggere la tua mente?”
Inizia con gli esempi. Una spec può essere valida e comunque inutile se ogni request e response è astratta. Per ogni operazione, includi almeno un esempio realistico di richiesta e una risposta di successo. Per gli errori, un esempio per ogni fallimento comune (auth, validazione) è quasi sempre sufficiente.
Poi controlla la coerenza. Se un endpoint restituisce { "error": "..." } e un altro { "message": "..." }, i client finiranno con logiche ramificate ovunque. Scegli una sola shape di errore e riutilizzala, insieme a codici di stato prevedibili.
Una checklist breve:
Un trucco pratico: scegli un endpoint, fai finta di non aver mai visto l'API e rispondi “Cosa invio, cosa ricevo indietro e cosa si rompe?” Se l'OpenAPI non può rispondere chiaramente, non è pronta.
Questo workflow ripaga quando viene eseguito regolarmente, non solo durante un rilascio affannoso. Scegli una regola semplice e rispettala: eseguila ogni volta che un endpoint cambia e di nuovo prima di pubblicare una spec aggiornata.
Mantieni la ownership semplice. Chi cambia un endpoint aggiorna le note di comportamento e la bozza di spec. Una seconda persona revisiona il “spec vs implementation” come una code review. QA o colleghi del support spesso sono ottimi revisori perché individuano risposte poco chiare e edge case rapidamente.
Tratta le modifiche al contratto come modifiche al codice. Se usi un builder chat-driven come Koder.ai, fare uno snapshot prima di modifiche rischiose e usare rollback quando serve mantiene l'iterazione sicura. Koder.ai supporta anche l'esportazione del codice sorgente, il che rende più semplice mantenere spec e implementazione affiancate nel repo.
Una routine che di solito funziona senza rallentare i team:
Prossima azione: scegli un endpoint esistente. Scrivi 5-10 righe di note sul comportamento (input, output, casi di errore), genera una bozza OpenAPI da quelle note, validala, poi confrontala con l'implementazione in esecuzione. Risolvi una discrepanza, ritesta e ripeti. Dopo un endpoint, l'abitudine tende a consolidarsi.
Lo drift di OpenAPI è quando l'API che effettivamente esegui non corrisponde più al file OpenAPI che le persone condividono. La spec potrebbe non contenere nuovi campi, codici di stato o regole di autenticazione, oppure potrebbe descrivere un comportamento “ideale” che il server non segue.
Conta perché i client (app, altri servizi, SDK generati, test) prendono decisioni basate sul contratto, non su ciò che il server “di solito” fa.
I problemi per i team client spesso appaiono così: una mobile app si aspetta 201 ma riceve 200, un SDK non riesce a deserializzare una risposta perché un campo è stato rinominato, o la gestione degli errori fallisce perché le shape degli errori sono diverse.
Anche quando nulla si rompe, i team perdono fiducia e smettono di usare la spec, eliminando il tuo sistema di allerta precoce.
Perché il codice riflette il comportamento attuale, inclusi bachi o stranezze che forse non vuoi promettere a lungo termine.
Un approccio migliore: scrivi prima il comportamento intenzionale (input, output, errori), poi verifica che l'implementazione corrisponda. Questo ti dà un contratto applicabile, invece di un'istantanea delle route di oggi.
Per ogni endpoint raccogli:
Scegli una shape di errore e riutilizzala ovunque.
Un default semplice può essere una di queste due opzioni:
{ "error": "message" }, oppure{ "error": { "code": "...", "message": "...", "details": ... } }Rendila coerente tra endpoint e esempi. La coerenza conta più della sofisticazione perché i client tenderanno a codificare rigidamente questa shape.
Dai a Claude Code le tue note di comportamento e istruzioni stringenti, e digli di non inventare campi.
Istruzioni pratiche:
TODO in the spec and list it under ASSUMPTIONS.”Error) and reference them.”Valida prima la spec internamente:
201)Questo intercetta file OpenAPI “di desiderio” prima ancora di guardare la produzione.
Tratta l'API in esecuzione come ciò che gli utenti sperimentano oggi e prendi decisioni caso per caso:
Mantieni le modifiche piccole (un endpoint o una risposta alla volta) per poterle ritestare velocemente.
Validazione server-side: rifiutare rapidamente richieste che violano il contratto e restituire un errore chiaro (status + codice/shape).
Validazione client-side: rilevare cambiamenti breaking risposte prima che arrivino agli utenti, asserendo solo ciò su cui davvero fai affidamento:
Evita di asserire ogni campo opzionale così i test falliscono per rotture reali, non per aggiunte innocue.
Una routine pratica:
Se usi Koder.ai, tieni il file OpenAPI vicino al codice, fai snapshot prima di modifiche rischiose e rollback se una modifica crea confusione.
Se riesci a scrivere una richiesta concreta e due risposte, di solito hai abbastanza materiale per bozzare una spec veritiera.
Dopo la generazione, controlla prima la sezione ASSUMPTIONS: lì si vede se il modello ha indovinato qualcosa che non va bene.