Use Cases (Actualizado: 3/6/2026)

Claude Code y OpenAPI 3.1: guía práctica con Swagger y TypeScript

Crea especificaciones OpenAPI 3.1 con Claude Code, valida con Swagger y genera clientes TypeScript.

Claude Code y OpenAPI 3.1: guía práctica con Swagger y TypeScript

Claude Code puede escribir un archivo OpenAPI en pocos minutos. El problema aparece cuando ese archivo se publica sin revisar: puede inventar campos a partir de una pantalla, añadir valores de enum que no existen en la base de datos o cambiar el formato de error entre endpoints.

En esta guía usaremos Claude Code como asistente para mantener contratos, no como autor infalible de esquemas. Vas a crear una especificación OpenAPI 3.1, validarla, generar un cliente TypeScript y un stub de servidor, y añadir una regla sencilla para detectar errores típicos de especificaciones generadas por IA. OpenAPI describe endpoints REST, cuerpos de petición, respuestas, autenticación y errores en un formato legible por herramientas. Swagger es el ecosistema que muchos equipos usan para editar, visualizar y revisar esos documentos.

Masa probó este flujo con una API pequeña de pedidos. El prompt inicial, “lee el repositorio y crea OpenAPI”, produjo un estado cancelled que sonaba razonable pero no existía en el dominio. El resultado mejoró cuando el prompt indicó qué archivos leer, prohibió campos no verificados, ejecutó validaciones y dejó las dudas fuera del esquema público.

Usa siempre fuentes oficiales. Al 3 de junio de 2026, la OpenAPI Specification latest ya es 3.2.0, pero esta guía fija los ejemplos en openapi: 3.1.0 por compatibilidad con generadores. Para los detalles de 3.1 usa OpenAPI Specification 3.1.2, para edición la documentación de Swagger Editor, y para generación OpenAPI Generator usage, typescript-fetch generator y typescript-nestjs-server generator. Para OpenAPI 3.1, revisa el soporte de Swagger Editor Next en la documentación actual antes de confiar en un editor antiguo.

Para completar el flujo, consulta también la guía de desarrollo de APIs, la guía de pruebas de API, las buenas prácticas de seguridad y las buenas prácticas de CLAUDE.md.

flowchart LR
  A["Implementación, DB, tests"] --> B["Claude Code redacta OpenAPI"]
  B --> C["Validación Swagger y CLI"]
  C --> D["Generar cliente TypeScript"]
  C --> E["Pruebas de contrato"]
  C --> F["Revisión de seguridad"]
  D --> G["Frontend o partners"]
  E --> H["Gate de publicación CI"]
  F --> H

Casos de uso reales

CasoQué delegar a Claude CodeQué decide el equipo
Documentar una API existenteRutas, modelos, códigos HTTP y autenticaciónCampos públicos, compatibilidad y nombres
Diseñar contrato antes del códigoBorrador OpenAPI 3.1, ejemplos y comandosReglas de negocio y política de errores
Integrar frontendCliente TypeScript y ejemplos de llamadaUX, reintentos y mensajes al usuario
Pruebas de contratooperationId, respuestas 4xx, enums y authPolítica de cambios incompatibles y excepciones
Revisión de seguridadSchemas públicos, auth, PII e IDs internosRiesgo legal, auditoría y compromisos con partners
Publicar API para partnersDescripciones, ejemplos y notas de authContratos, límites de uso y soporte

La regla práctica es simple: si el código, la base de datos, los tests o una decisión de producto no prueban un detalle del esquema, Claude Code no debe publicarlo.

Proyecto mínimo

Requiere Node.js 20 o superior. OpenAPI Generator usa Java para generar código, así que instala Java si quieres ejecutar los comandos de generación.

mkdir openapi-claude-demo
cd openapi-claude-demo
npm init -y
npm install -D @openapitools/openapi-generator-cli js-yaml
mkdir specs generated scripts

Configura package.json:

{
  "type": "module",
  "scripts": {
    "validate:openapi": "openapi-generator-cli validate -i specs/openapi.yaml",
    "lint:contract": "node scripts/check-openapi-rules.mjs",
    "test:contract": "node --test scripts/contract.test.mjs",
    "generate:client": "openapi-generator-cli generate -i specs/openapi.yaml -g typescript-fetch -o generated/client --additional-properties=supportsES6=true,npmName=@example/orders-client,npmVersion=0.1.0",
    "generate:server": "openapi-generator-cli generate -i specs/openapi.yaml -g typescript-nestjs-server -o generated/server",
    "contract": "npm run validate:openapi && npm run lint:contract && npm run test:contract && npm run generate:client"
  },
  "devDependencies": {
    "@openapitools/openapi-generator-cli": "latest",
    "js-yaml": "latest"
  }
}

Crea specs/openapi.yaml. En OpenAPI 3.1, para valores nulos usa JSON Schema, por ejemplo type: [string, "null"], en lugar de nullable: true.

openapi: 3.1.0
info:
  title: Orders API
  version: 0.1.0
  description: Contract-first sample API for order intake.
servers:
  - url: https://api.example.com/v1
paths:
  /orders:
    post:
      operationId: createOrder
      summary: Create an order
      tags: [orders]
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateOrderRequest"
      responses:
        "201":
          description: Order created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Order"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
    get:
      operationId: listOrders
      summary: List orders
      tags: [orders]
      responses:
        "200":
          description: Orders list
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Order"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Unauthorized:
      description: Missing or invalid token
  schemas:
    CreateOrderRequest:
      type: object
      additionalProperties: false
      required: [customerEmail, items]
      properties:
        customerEmail:
          type: string
          format: email
        note:
          type: [string, "null"]
          maxLength: 500
        items:
          type: array
          minItems: 1
          items:
            $ref: "#/components/schemas/OrderItemInput"
    OrderItemInput:
      type: object
      additionalProperties: false
      required: [sku, quantity]
      properties:
        sku:
          type: string
        quantity:
          type: integer
          minimum: 1
    Order:
      type: object
      additionalProperties: false
      required: [id, customerEmail, status, items, createdAt]
      properties:
        id:
          type: string
          format: uuid
        customerEmail:
          type: string
          format: email
        status:
          type: string
          enum: [pending, paid]
        note:
          type: [string, "null"]
        items:
          type: array
          items:
            $ref: "#/components/schemas/OrderItemInput"
        createdAt:
          type: string
          format: date-time
    ErrorResponse:
      type: object
      additionalProperties: false
      required: [code, message]
      properties:
        code:
          type: string
          enum: [invalid_request, unauthorized]
        message:
          type: string

Añade una revisión local para detectar marcadores temporales, patrones antiguos y campos sensibles:

// scripts/check-openapi-rules.mjs
import { readFileSync } from "node:fs";

const spec = readFileSync("specs/openapi.yaml", "utf8");
const forbidden = [
  { pattern: /\bTBD\b|\bTODO\b|placeholder/i, reason: "unfinished placeholder" },
  { pattern: /nullable:\s*true/, reason: "OpenAPI 3.1 should use JSON Schema null types" },
  { pattern: /password|secret|clientSecret|apiKey/i, reason: "review sensitive fields before publishing" }
];

const errors = forbidden
  .filter((rule) => rule.pattern.test(spec))
  .map((rule) => `- ${rule.reason}`);

if (!spec.includes("additionalProperties: false")) {
  errors.push("- schemas should explicitly decide additionalProperties");
}

if (errors.length > 0) {
  console.error("Contract review failed:\n" + errors.join("\n"));
  process.exit(1);
}

console.log("Contract review passed.");

Añade una prueba de contrato que pueda ejecutarse en CI. No sustituye a las pruebas contra el servidor real; verifica que el contrato público mantenga operationId, seguridad en operaciones mutantes, respuestas 4xx compartidas y el enum actual de Order.status.

// scripts/contract.test.mjs
import { readFileSync } from "node:fs";
import assert from "node:assert/strict";
import test from "node:test";
import { load } from "js-yaml";

const doc = load(readFileSync("specs/openapi.yaml", "utf8"));
const httpMethods = new Set(["get", "put", "post", "delete", "patch", "options", "head", "trace"]);

function operations() {
  return Object.entries(doc.paths ?? {}).flatMap(([path, pathItem]) =>
    Object.entries(pathItem)
      .filter(([method]) => httpMethods.has(method))
      .map(([method, operation]) => ({ path, method, operation }))
  );
}

test("operationId is unique and camelCase", () => {
  const ids = operations().map(({ operation }) => operation.operationId);
  assert.equal(new Set(ids).size, ids.length);
  for (const id of ids) {
    assert.match(id, /^[a-z][A-Za-z0-9]*$/);
  }
});

test("mutating operations require security", () => {
  for (const { path, method, operation } of operations()) {
    if (["get", "head", "options"].includes(method)) continue;
    assert.ok(operation.security?.length, `${method.toUpperCase()} ${path} must declare security`);
  }
});

test("client-visible 4xx responses reuse shared components", () => {
  for (const { path, method, operation } of operations()) {
    for (const [status, response] of Object.entries(operation.responses ?? {})) {
      if (!status.startsWith("4")) continue;
      assert.ok(response.$ref?.startsWith("#/components/responses/"), `${method.toUpperCase()} ${path} ${status}`);
    }
  }
});

test("Order status enum matches the current implementation decision", () => {
  const status = doc.components.schemas.Order.properties.status;
  assert.deepEqual(status.enum, ["pending", "paid"]);
});

Ejecuta:

npm run validate:openapi
npm run lint:contract
npm run test:contract
npm run generate:client
npm run generate:server

Los archivos generados no son la fuente de verdad. Corrige specs/openapi.yaml y vuelve a generar.

Prompt recomendado

Crea un contrato OpenAPI 3.1 para la API de pedidos.
Lee primero src/routes/orders.ts, src/domain/order.ts, prisma/schema.prisma y tests/orders.test.ts.
No inventes campos, enums ni códigos de error no demostrados por código, esquema, tests o nota de producto.
Coloca dudas en x-claude-review, no en schemas públicos.
No uses nullable: true. Usa operationId estable en camelCase.
Declara security en operaciones protegidas. Separa campos internos, PII y candidatos a secret en x-claude-review antes de publicarlos.
Ejecuta npm run validate:openapi, npm run lint:contract y npm run test:contract, y corrige fallos.
Devuelve el diff, un ejemplo de cliente TypeScript, notas de seguridad y dudas para revisión humana.

Pruebas de contrato y seguridad

En una API SaaS o de partners, revisar OpenAPI no es solo corregir texto. Separa cuatro carriles: revisión de especificación, revisión del cliente generado, pruebas de contrato y seguridad. La especificación cubre rutas, métodos, schemas, estados y ejemplos. El cliente generado valida que typescript-fetch produzca tipos útiles. Las pruebas de contrato frenan auth ausente, errores inconsistentes y enums rotos. Seguridad revisa campos públicos, PII, IDs internos, URLs de servidor y posibles secretos.

Claude Code puede inventariar diferencias, redactar pruebas y preparar la tabla de revisión. El equipo sigue siendo responsable de decidir qué se publica, qué rate limit se promete, qué datos tienen riesgo legal y qué evidencia necesita auditoría.

Fallos frecuentes

El primer fallo es inventar esquemas: cancelled, refunded o adminNote aparecen porque parecen útiles. El segundo es tener errores inconsistentes, como { message } en una ruta y { error: { code } } en otra. El tercero es mezclar hábitos de OpenAPI 3.0, especialmente nullable: true, dentro de un documento 3.1. El cuarto es editar a mano el cliente generado. El quinto es revisar solo la vista Swagger y olvidar operationId, autenticación, ejemplos y compatibilidad de enums.

CTA de formación

La limpieza de OpenAPI se vende bien como formación o consultoría porque deja entregables claros: especificación, cliente TypeScript, stub de servidor, prueba de contrato, validación y checklist de CI. Para trabajar de forma individual, usa los productos y plantillas de ClaudeCodeLab. Para un rollout con repositorio real, CLAUDE.md, pruebas de API y revisión de seguridad, usa formación y consultoría Claude Code.

Resultado probado

En la prueba de Masa, el prompt libre añadió estados no implementados y cambió el formato de error. Con archivos obligatorios, reglas de no invención, openapi-generator-cli validate, el script local y node --test, la revisión humana se redujo a cuatro decisiones: campos públicos, crecimiento futuro de enums, texto de errores de autenticación y posible fuga de datos internos. OpenAPI funcionó mejor como contrato compartido que como documento delegado a ciegas.

#Claude Code #OpenAPI #Swagger #API design #REST
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.