Aprende a generar OpenAPI a partir del comportamiento con Claude Code, compararlo con tu implementación y crear ejemplos simples de validación para cliente y servidor.

Un contrato OpenAPI es una descripción compartida de tu API: qué endpoints existen, qué se envía, qué se recibe y cómo son los errores. Es el acuerdo entre el servidor y cualquier cosa que lo llame (una app web, una app móvil u otro servicio).
El problema es la deriva. La API en ejecución cambia, pero el spec no. O el spec se “limpia” para verse mejor que la realidad, mientras la implementación sigue devolviendo campos extraños, códigos de estado faltantes o formas de error inconsistentes. Con el tiempo, la gente deja de confiar en el archivo OpenAPI y se convierte en otro documento que todos ignoran.
La deriva suele surgir por presiones normales: se lanza una solución rápida sin actualizar el spec, se añade un campo opcional “temporalmente”, la paginación evoluciona o los equipos actualizan diferentes “fuentes de la verdad” (código backend, una colección de Postman y un archivo OpenAPI).
Mantener la honestidad significa que el spec coincide con el comportamiento real. Si la API a veces devuelve 409 por un conflicto, eso debe estar en el contrato. Si un campo es nullable, dilo. Si se requiere auth, no lo dejes vago.
Un buen flujo de trabajo te deja con:
Este último punto importa porque un contrato solo ayuda cuando se aplica. Un spec honesto más comprobaciones repetibles convierte la “documentación de la API” en algo en lo que los equipos pueden confiar.
Si empiezas leyendo código o copiando rutas, tu OpenAPI describirá lo que existe hoy, incluidas rarezas que quizá no quieras prometer. En su lugar, describe lo que la API debería hacer para un llamador, y usa el spec para verificar que la implementación coincide.
Antes de escribir YAML o JSON, recoge un pequeño conjunto de hechos por endpoint:
Luego escribe el comportamiento como ejemplos. Los ejemplos te obligan a ser específico y hacen más fácil elaborar un contrato consistente.
Para una API de Tasks, un ejemplo de camino feliz podría ser: “Crear una tarea con title y recibir id, title, status y createdAt.” Añade fallos comunes: “Falta title devuelve 400 con {\"error\":\"title is required\"}” y “Sin auth devuelve 401.” Si ya conoces casos límite, inclúyelos: si se permiten títulos duplicados y qué sucede cuando no existe un ID de tarea.
Captura reglas como oraciones simples que no dependan de detalles del código:
title es obligatorio y tiene entre 1 y 120 caracteres.”limit esté establecido (máx 200).”dueDate es date-time en ISO 8601.”Finalmente, decide el alcance de tu v1. Si no estás seguro, mantén v1 pequeño y claro (create, read, list, update status). Deja búsqueda, actualizaciones en masa y filtros complejos para después para que el contrato siga siendo creíble.
Antes de pedirle a Claude Code que redacte un spec, escribe notas de comportamiento en un formato pequeño y repetible. El objetivo es dificultar que se “rellenen huecos” con conjeturas.
Una buena plantilla es lo bastante corta como para que realmente la uses, pero consistente como para que dos personas describan el mismo endpoint de forma parecida. Mantente enfocado en lo que hace la API, no en cómo está implementada.
Usa un bloque por 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):
Escribe al menos una petición concreta y dos respuestas. Incluye códigos de estado y cuerpos JSON realistas con nombres de campo reales. Si un campo es opcional, muestra un ejemplo en el que falta.
Señala los casos límite explícitamente. Estos son los puntos donde los specs se vuelven falsos más tarde porque todo el mundo asumió algo distinto: resultados vacíos, IDs inválidos (400 vs 404), duplicados (409 vs comportamiento idempotente), fallos de validación y límites de paginación.
También anota los tipos de datos en palabras antes de pensar en esquemas: strings vs numbers, formatos date-time, booleans y enums (lista de valores permitidos). Esto evita un esquema “bonito” que no coincide con payloads reales.
Claude Code funciona mejor cuando lo tratas como un escriba cuidadoso. Dale tus notas de comportamiento y reglas estrictas sobre cómo debe formarse el OpenAPI. Si solo dices “escribe un spec OpenAPI”, normalmente obtendrás conjeturas, nombres inconsistentes y casos de error faltantes.
Pega tus notas de comportamiento primero y luego añade un bloque de instrucciones claro. Un prompt práctico se ve así:
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.
Después de obtener el borrador, revisa las ASSUMPTIONS primero. Ahí es donde se gana o se pierde la honestidad. Aprueba lo que sea correcto, corrige lo que esté mal y vuelve a ejecutar con notas actualizadas.
Para mantener la nomenclatura consistente, establece convenciones desde el inicio y cúmplelas. Por ejemplo: un patrón estable para operationId, nombres de tags solo sustantivos, nombres de esquema en singular, un Error compartido y un nombre de esquema de auth usado en todas partes.
Si trabajas en un entorno tipo vibe-coding como Koder.ai, ayuda guardar el YAML como un archivo real pronto e iterar en pequeños diffs. Así verás qué cambios vienen de decisiones de comportamiento aprobadas frente a detalles que el modelo adivinó.
Antes de comparar nada con producción, asegúrate de que el archivo OpenAPI sea internamente consistente. Este es el lugar más rápido para atrapar el pensamiento deseoso y el lenguaje vago.
Lee cada endpoint como si fueras el desarrollador del cliente. Concéntrate en lo que un llamador debe enviar y en lo que puede confiar que recibirá.
Un repaso práctico:
Las respuestas de error merecen atención extra. Elige una forma compartida y reutilízala en todas partes. Algunos equipos lo mantienen simple ({ error: string }), otros usan un objeto ({ error: { code, message, details } }). Cualquiera puede funcionar, pero no los mezcles entre endpoints y ejemplos. Si lo haces, el código cliente acumulará casos especiales.
Un escenario de sanity rápido ayuda. Si POST /tasks requiere title, el esquema debe marcarlo como requerido, la respuesta de fallo debe mostrar el cuerpo de error que realmente devuelves y la operación debe indicar claramente si se requiere auth.
Una vez que el spec se lea como tu comportamiento previsto, trata a la API en ejecución como la verdad de lo que experimentan los clientes hoy. El objetivo no es “ganar” entre spec y código, sino sacar a la luz diferencias pronto y tomar una decisión clara sobre cada una.
Para una primera pasada, muestras reales de petición/respuesta suelen ser la opción más simple. Los logs y las pruebas automatizadas también funcionan si son fiables.
Atento a desajustes comunes: endpoints presentes en un lugar pero no en otro, diferencias en nombres o formas de campos, diferencias en códigos de estado (200 vs 201, 400 vs 422), comportamientos no documentados (paginación, ordenación, filtros) y diferencias de auth (el spec dice público, el código requiere token).
Ejemplo: tu OpenAPI dice que POST /tasks devuelve 201 con {id,title}. Llamas a la API en ejecución y obtienes 200 más {id,title,createdAt}. Eso no es “suficientemente cercano” si generas SDKs desde el spec.
Antes de editar nada, decide cómo resolver conflictos:
Mantén cada cambio pequeño y revisable: un endpoint, una respuesta, un ajuste de esquema. Es más fácil de revisar y más fácil de re-probar.
Una vez que tengas un spec en el que confíes, conviértelo en pequeños ejemplos de validación. Esto es lo que evita que la deriva se cuele de nuevo.
En el servidor, validar significa fallar rápido cuando una petición no coincide con el contrato y devolver un error claro. Eso protege tus datos y hace que los bugs sean más fáciles de localizar.
Una forma simple de expresar ejemplos de validación en servidor es escribirlos como casos con tres partes: input, salida esperada y error esperado (un código de error o patrón de mensaje, no el texto exacto).
Ejemplo (el contrato dice que title es obligatorio y debe tener 1 a 120 chars):
{\n \"name\": \"Create task without title returns 400\",\n \"request\": {\"method\": \"POST\", \"path\": \"/tasks\", \"body\": {\"title\": \"\"}},\n \"expect\": {\"status\": 400, \"body\": {\"error\": {\"code\": \"VALIDATION_ERROR\"}}}\n}\n```
### Validación en cliente (detectar cambios rompientes temprano)
En el cliente, la validación trata de detectar deriva antes que los usuarios la noten. Si el servidor empieza a devolver otra forma o desaparece un campo obligatorio, tus pruebas deberían avisarlo.
Mantén las comprobaciones de cliente enfocadas en lo que realmente dependes, como “una task tiene `id`, `title`, `status`.” Evita afirmar cada campo opcional o el orden exacto. Quieres fallos por cambios rompientes, no por adiciones inocuas.
Algunas guías que mantienen las pruebas legibles:
- Prefiere comprobar presencia y tipo sobre valores exactos.
- Afirma solo campos requeridos a menos que un campo opcional sea crítico para tu feature.
- Para errores, comprueba el estado y un código de error, no mensajes completos.
- Permite campos extra a menos que el contrato explícitamente los prohíba.
Si usas Koder.ai, puedes generar y mantener estos casos de ejemplo junto al archivo OpenAPI, y actualizarlos como parte de la misma revisión cuando cambia el comportamiento.
## Escenario de ejemplo: un API simple de Tasks de extremo a extremo
Imagina una pequeña API con tres endpoints: `POST /tasks` crea una tarea, `GET /tasks` lista tareas y `GET /tasks/{id}` devuelve una tarea.
Empieza escribiendo unos ejemplos concretos para un endpoint, como si se lo explicaras a un tester.
Para `POST /tasks`, el comportamiento previsto podría ser:
- Éxito: enviar `{ \"title\": \"Buy milk\" }` y recibir 201 con un nuevo objeto task, incluyendo `id`, `title` y `done:false`.
- Fallo 1: enviar `{}` y recibir 400 con un error como `{ \"error\": \"title is required\" }`.
- Fallo 2: enviar `{ \"title\": \"x\" }` (demasiado corto) y recibir 422 con `{ \"error\": \"title must be at least 3 characters\" }`.
Cuando Claude Code redacte el OpenAPI, el fragmento para este endpoint debería capturar el esquema, los códigos de estado y ejemplos realistas:
```yaml
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\" }
Un desajuste común es sutil: la API en ejecución devuelve 200 en lugar de 201, o devuelve { \"taskId\": 123 } en vez de { \"id\": \"t_123\" }. Ese tipo de diferencia “casi igual” rompe los clientes generados.
Arréglalo eligiendo una única fuente de verdad. Si el comportamiento previsto es correcto, cambia la implementación para devolver 201 y la forma Task acordada. Si el comportamiento en producción ya se usa, actualiza el spec (y las notas de comportamiento) para reflejar la realidad, luego añade la validación y respuestas de error faltantes para que los clientes no se sorprendan.
Un contrato se vuelve deshonesto cuando deja de describir reglas y empieza a describir lo que tu API devolvió un buen día. Una prueba simple: ¿podría una nueva implementación pasar este spec sin copiar las rarezas actuales?
Una trampa es el sobreajuste. Capturas una respuesta y la conviertes en ley. Ejemplo: tu API actualmente devuelve dueDate: null para cada tarea, así que el spec dice que el campo es siempre nullable. Pero la regla real podría ser “requerido cuando el status es scheduled.” El contrato debería expresar la regla, no solo el dataset actual.
Los errores son donde la honestidad suele romperse. Es tentador especificar solo respuestas exitosas porque quedan limpias. Pero los clientes necesitan lo básico: 401 cuando falta el token, 403 para acceso prohibido, 404 para IDs desconocidos y un error de validación consistente (400 o 422).
Otros patrones que causan problemas:
taskId en una ruta y id en otra, o priority como string en una respuesta y número en otra).string, todo opcional).Un buen contrato es verificable. Si no puedes escribir una prueba que falle a partir del spec, aún no es honesto.
Antes de entregar un archivo OpenAPI a otro equipo (o pegarlo en docs), haz una pasada rápida para “¿puede alguien usar esto sin leerte la mente?”
Empieza por los ejemplos. Un spec puede ser válido y aun así inútil si cada petición y respuesta es abstracta. Para cada operación, incluye al menos un ejemplo realista de petición y una respuesta de éxito. Para errores, un ejemplo por fallo común (auth, validación) suele ser suficiente.
Luego verifica la consistencia. Si un endpoint devuelve { \"error\": \"...\" } y otro devuelve { \"message\": \"...\" }, los clientes tendrán lógica ramificada por todas partes. Elige una forma de error única y reutilízala, junto con códigos de estado predecibles.
Una lista de comprobación corta:
Un truco práctico: elige un endpoint, finge que nunca has visto la API y responde “¿Qué envío, qué recibo y qué se rompe?” Si el OpenAPI no puede responder eso claramente, no está listo.
Este flujo de trabajo rinde cuando se ejecuta regularmente, no solo durante un apuro de releases. Elige una regla simple y síguela: ejecútala cuando cambie un endpoint y otra vez antes de publicar un spec actualizado.
Mantén la propiedad simple. La persona que cambia un endpoint actualiza las notas de comportamiento y el borrador del spec. Una segunda persona revisa el “spec vs implementation” como una revisión de código. QA o compañeros de soporte suelen ser buenos revisores porque detectan respuestas poco claras y casos límite rápidamente.
Trata las ediciones de contrato como ediciones de código. Si usas un builder guiado por chat como Koder.ai, tomar un snapshot antes de ediciones riesgosas y usar rollback cuando haga falta mantiene la iteración segura. Koder.ai también permite exportar código fuente, lo que facilita mantener el spec y la implementación lado a lado en tu repo.
Una rutina que suele funcionar sin ralentizar a los equipos:
Próxima acción: elige un endpoint que ya exista. Escribe 5-10 líneas de notas de comportamiento (entradas, salidas, casos de error), genera un borrador OpenAPI desde esas notas, valídalo y compáralo con la implementación en ejecución. Corrige una discrepancia, vuelve a probar y repite. Después de un endpoint, el hábito suele quedarse.
La deriva de OpenAPI es cuando la API que realmente ejecutas ya no coincide con el archivo OpenAPI que se comparte. El spec puede no incluir campos nuevos, códigos de estado o reglas de autenticación, o puede describir un comportamiento “ideal” que el servidor no sigue.
Importa porque los clientes (apps, otros servicios, SDKs generados, pruebas) toman decisiones basadas en el contrato, no en lo que tu servidor “suele” hacer.
Las roturas en clientes se vuelven aleatorias y difíciles de depurar: una app móvil espera 201 y recibe 200, un SDK no puede deserializar una respuesta porque se renombró un campo, o el manejo de errores falla porque las formas de error difieren.
Incluso cuando nada se bloquea, los equipos pierden confianza y dejan de usar el spec, lo que elimina tu sistema de alerta temprana.
Porque el código refleja el comportamiento actual, incluidas las rarezas accidentales que quizá no quieras prometer a largo plazo.
Un mejor enfoque por defecto es: escribe primero el comportamiento previsto (entradas, salidas, errores) y luego verifica que la implementación coincida. Eso te da un contrato que puedes hacer cumplir en lugar de una foto de las rutas de hoy.
Por cada endpoint captura:
Elige una forma de cuerpo de error y úsala en todos lados.
Una opción simple por defecto es:
{ "error": "message" }, o{ "error": { "code": "...", "message": "...", "details": ... } }Luego mantenlo consistente entre endpoints y ejemplos. La consistencia importa más que la sofisticación porque los clientes acabarán codificando esta forma.
Dale a Claude Code tus notas de comportamiento y reglas estrictas, y dile que no invente campos. Un conjunto práctico de instrucciones:
TODO en el spec y enuméralo bajo ASSUMPTIONS.”Error) y referencia a ellos.”Después de generar, revisa primero las . Ahí es donde empieza la falta de honestidad si aceptas conjeturas.
Valida el spec en sí primero:
201)Esto detecta archivos OpenAPI “ilusorios” antes de mirar el comportamiento en producción.
Trata la API en ejecución como lo que los usuarios experimentan hoy, y decide caso por caso:
Mantén los cambios pequeños (un endpoint o una respuesta a la vez) para poder volver a probar rápido.
La validación en servidor debe rechazar peticiones que violen el contrato y devolver un error claro y consistente (código de estado + código/forma de error).
La validación en cliente debe detectar cambios rompientes en las respuestas temprano, afirmando solo lo que realmente necesitas:
Evita afirmar cada campo opcional para que las pruebas fallen por cambios críticos, no por adiciones inocuas.
Una rutina práctica es:
Si trabajas en Koder.ai, puedes mantener el archivo OpenAPI junto al código, usar snapshots antes de ediciones riesgosas y revertir si un cambio de spec/código se complica.
Si puedes escribir una petición concreta y dos respuestas, normalmente tienes suficiente para redactar un spec veraz.