Claude Code com OpenAPI 3.1: validação Swagger e geração TypeScript
Crie specs OpenAPI 3.1 com Claude Code, valide com Swagger e gere clientes TypeScript confiáveis.
Claude Code consegue criar uma especificação OpenAPI rapidamente. O risco começa quando esse arquivo vira contrato sem revisão. A IA pode inferir campos a partir de uma tela, criar valores de enum que não existem no banco ou mudar o formato de erro entre endpoints.
Neste guia, vamos usar Claude Code como assistente de manutenção de contrato, não como dono da verdade. Você vai criar uma especificação OpenAPI 3.1, validar o arquivo, gerar um cliente TypeScript e um stub de servidor, além de adicionar uma checagem simples contra schemas alucinados. OpenAPI descreve endpoints REST, requests, responses, autenticação e erros em formato legível por ferramentas. Swagger é o ecossistema usado para editar, visualizar e revisar esses documentos.
Masa testou o fluxo em uma API pequena de pedidos. O prompt livre gerou um status cancelled plausível, mas inexistente no modelo. O resultado ficou confiável quando o prompt definiu os arquivos a ler, proibiu campos não comprovados, executou validações e colocou dúvidas fora do schema público.
Referências oficiais: em 3 de junho de 2026, OpenAPI Specification latest aponta para 3.2.0, mas os exemplos deste artigo ficam em openapi: 3.1.0 por compatibilidade com geradores. Use OpenAPI Specification 3.1.2, Swagger Editor documentation, OpenAPI Generator usage, typescript-fetch generator e typescript-nestjs-server generator. Para OpenAPI 3.1, confirme o suporte do Swagger Editor Next na documentação atual.
Leia também o guia de desenvolvimento de APIs, o guia de testes de API, as boas práticas de segurança e as boas práticas de CLAUDE.md.
flowchart LR
A["Implementação, DB, testes"] --> B["Claude Code rascunha OpenAPI"]
B --> C["Validação Swagger e CLI"]
C --> D["Cliente TypeScript"]
C --> E["Testes de contrato"]
C --> F["Revisão de segurança"]
D --> G["Frontend ou parceiros"]
E --> H["Gate de CI"]
F --> H
Casos de uso
| Caso | Claude Code faz | Time decide |
|---|---|---|
| Documentar API existente | Rotas, modelos, status HTTP, autenticação | Campos públicos, compatibilidade, nomes |
| Desenvolvimento contract-first | Rascunho OpenAPI 3.1, exemplos, comandos | Regras de negócio, erros, escopo |
| Integração frontend | Cliente TypeScript e exemplos | UX, retry, mensagens |
| Testes de contrato | operationId, respostas 4xx, enums, auth | Política de breaking change e exceções |
| Revisão de segurança | Schemas públicos, auth, PII, IDs internos | Risco legal, auditoria, promessas a parceiros |
| API para parceiros | Descrições Swagger, exemplos, auth | Contratos, limites, suporte |
Se código, banco, testes ou decisão de produto não provam um detalhe, ele não deve entrar no schema público.
Setup copiável
Use Node.js 20+. O OpenAPI Generator usa Java para gerar código.
mkdir openapi-claude-demo
cd openapi-claude-demo
npm init -y
npm install -D @openapitools/openapi-generator-cli js-yaml
mkdir specs generated scripts
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"
}
}
specs/openapi.yaml:
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"
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"]
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]
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
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.");
Adicione também um teste de contrato para CI. Ele verifica o contrato público: operationId, segurança em operações mutantes, respostas 4xx compartilhadas e o enum atual 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"]);
});
Execute:
npm run validate:openapi
npm run lint:contract
npm run test:contract
npm run generate:client
npm run generate:server
Prompt para Claude Code
Crie um contrato OpenAPI 3.1 para a API de pedidos.
Leia src/routes/orders.ts, src/domain/order.ts, prisma/schema.prisma e tests/orders.test.ts.
Não invente campos, enums ou códigos de erro sem prova em código, schema, testes ou nota de produto.
Coloque dúvidas em x-claude-review, não em schemas públicos.
Não use nullable: true. Use operationId estável em camelCase.
Declare security em operações protegidas. Campos internos, PII e possíveis secrets ficam em x-claude-review antes de schemas públicos.
Execute npm run validate:openapi, npm run lint:contract e npm run test:contract, depois corrija falhas.
Retorne o diff, um exemplo de cliente TypeScript, notas de segurança e pontos para revisão humana.
Testes de contrato e segurança
Em APIs SaaS ou para parceiros, revisar OpenAPI não é só revisar texto. Separe spec review, client gerado, testes de contrato e segurança. Spec review olha paths, métodos, schemas, status e exemplos. O client gerado valida tipos typescript-fetch e null/optional. Testes de contrato bloqueiam auth ausente, erros inconsistentes e enums quebrados. Segurança revisa campos públicos, PII, IDs internos, URLs de servidor e possíveis secrets.
Claude Code pode organizar diffs, rascunhar testes e preparar a tabela de revisão. A equipe continua decidindo o que pode ser publicado, quais rate limits serão prometidos, quais riscos legais existem e quais evidências de auditoria são necessárias.
Armadilhas comuns
As falhas mais comuns são schemas inventados, formatos de erro inconsistentes, hábitos de OpenAPI 3.0 dentro de arquivos 3.1, edição manual do código gerado e revisão apenas visual no Swagger. A fonte da verdade é specs/openapi.yaml; cliente e stub devem ser regenerados.
Treinamento e consultoria
OpenAPI é um bom tema de treinamento porque entrega resultados concretos: spec, cliente TypeScript, stub de servidor, teste de contrato, validação e checklist de CI. Quem trabalha sozinho pode começar pelos produtos ClaudeCodeLab com prompts e checklists. Times que precisam adaptar isso a um repositório real, CLAUDE.md, testes de API e revisão de segurança podem usar treinamento e consultoria Claude Code.
Verificação prática
No teste de Masa, o prompt livre adicionou status não implementados e mudou o envelope de erro. Com arquivos obrigatórios, regra de não inventar, openapi-generator-cli validate, script local e node --test, a revisão humana ficou concentrada em campos públicos, evolução de enums, mensagens de autenticação e possível vazamento de dados internos. OpenAPI funcionou como contrato compartilhado entre IA e equipe.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Workflow Obsidian para CLAUDE.md com Claude Code
Transforme notas de trabalho do Obsidian em notas operacionais CLAUDE.md para preservar contexto.
Claude Code Revenue CTA Routing: artigos para PDF, Gumroad e consultoria
Um fluxo com Claude Code para levar leitores ao PDF grátis, Gumroad ou consultoria conforme intenção.
Regras de handoff para equipes com Claude Code: evidências, permissões, rollback e receita
Formato prático para entregar trabalho do Claude Code com prova, permissões, rollback, PDF grátis, Gumroad e consultoria.