6 min

Gerar OpenAPI a partir do comportamento com Claude Code, honestamente

Aprenda a gerar OpenAPI a partir do comportamento com Claude Code, comparar com sua implementação e criar exemplos simples de validação cliente e servidor.

Gerar OpenAPI a partir do comportamento com Claude Code, honestamente

Por que contratos OpenAPI se desviam (e por que isso importa)

Um contrato OpenAPI é uma descrição compartilhada da sua API: quais endpoints existem, o que você envia, o que recebe de volta e como são os erros. É o acordo entre o servidor e qualquer coisa que o chame (um web app, app móvel ou outro serviço).

O problema é o drift. A API em execução muda, mas o spec não. Ou o spec é “limpo” para ficar mais apresentável do que a realidade, enquanto a implementação continua retornando campos estranhos, códigos de status faltantes ou formatos de erro inconsistentes. Com o tempo, as pessoas deixam de confiar no arquivo OpenAPI, e ele vira só mais um documento ignorado.

O drift geralmente vem das pressões normais: um conserto rápido é enviado sem atualizar o spec, um novo campo opcional é adicionado “temporariamente”, a paginação evolui, ou equipes atualizam fontes diferentes de verdade (código backend, uma coleção do Postman e um arquivo OpenAPI).

Manter honestidade significa que o spec corresponde ao comportamento real. Se a API às vezes retorna 409 por conflito, isso pertence ao contrato. Se um campo é nullable, diga isso. Se auth é exigido, não deixe vago.

Um bom fluxo de trabalho deixa você com:

  • Um arquivo OpenAPI que reflete comportamento pretendido e observado
  • Um conjunto simples de checagens para detectar drift cedo, antes que clientes quebrem
  • Exemplos concretos de validação cliente e servidor que você pode copiar para sua base de código

Esse último ponto importa porque um contrato só ajuda quando é aplicado. Um spec honesto mais checagens repetíveis transforma “documentação de API” em algo que as equipes possam confiar.

Comece pelo comportamento pretendido, não pelo código

Se você começar lendo código ou copiando rotas, seu OpenAPI descreverá o que existe hoje, incluindo esquisitices que talvez não queira prometer. Em vez disso, descreva o que a API deve fazer para um chamador, depois use o spec para verificar se a implementação corresponde.

Antes de escrever YAML ou JSON, colecione um pequeno conjunto de fatos por endpoint:

  • O que ele faz (método e caminho)
  • O que aceita (headers, query, path params, body)
  • O que retorna (código de sucesso, formato de resposta, headers chave)
  • O que pode falhar (erros prováveis, códigos de status, formato do body de erro)
  • Quem pode chamá-lo (auth e papéis, se relevante)

Então escreva o comportamento como exemplos. Exemplos forçam você a ser específico e facilitam rascunhar um contrato consistente.

Para uma API de Tasks, um caminho feliz pode ser: “Cria uma task com title e devolve id, title, status e createdAt.” Adicione falhas comuns: “Falta title retorna 400 com {\"error\":\"title is required\"}” e “Sem auth retorna 401.” Se você já conhece edge cases, inclua-os: se títulos duplicados são permitidos e o que acontece quando um ID de task não existe.

Capture regras como sentenças simples que não dependam de detalhes de código:

  • title é obrigatório e tem 1–120 caracteres.”
  • “List retorna até 50 itens a menos que limit seja definido (máx 200).”
  • dueDate é date-time ISO 8601.”
  • “Endpoints de escrita exigem token de usuário.”

Finalmente, decida o escopo da v1. Se estiver inseguro, mantenha a v1 pequena e clara (create, read, list, update status). Guarde busca, atualizações em lote e filtros complexos para depois, assim o contrato permanece crível.

Um template leve para descrever endpoints

Antes de pedir ao Claude Code para gerar um spec, escreva notas de comportamento em um formato pequeno e repetível. O objetivo é tornar difícil “preencher lacunas” com suposições.

Um bom template é curto o bastante para ser usado, mas consistente o suficiente para que duas pessoas descrevam o mesmo endpoint de forma semelhante. Mantenha o foco no que a API faz, não em como é implementada.

Template de nota de comportamento por endpoint

Use um bloco 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):

Escreva pelo menos uma requisição concreta e duas respostas. Inclua códigos de status e bodies JSON realistas com nomes de campo reais. Se um campo for opcional, mostre um exemplo onde ele está ausente.

Destaque edge cases explicitamente. São esses pontos que fazem o spec ficar falso mais tarde porque cada um assumiu algo diferente: resultados vazios, IDs inválidos (400 vs 404), duplicatas (409 vs comportamento idempotente), falhas de validação e limites de paginação.

Também anote tipos de dados em termos humanos antes de pensar em schemas: strings vs numbers, formatos date-time, booleans e enums (lista de valores permitidos). Isso evita um schema “bonito” que não bate com payloads reais.

Rascunhe o spec OpenAPI com Claude Code (prompting que funciona)

Claude Code funciona melhor quando você o trata como um escriba cuidadoso. Dê suas behavior notes e regras estritas sobre como o OpenAPI deve ser formado. Se você só disser “escreva um spec OpenAPI”, ele geralmente vai chutar nomes, ser inconsistente e esquecer casos de erro.

Cole suas behavior notes primeiro, depois adicione um bloco de instruções rígidas. Um prompt prático fica assim:

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.

Depois de receber o rascunho, leia as ASSUMPTIONS primeiro. É aí que a honestidade é ganha ou perdida. Aprove o que está correto, corrija o que está errado e rode novamente com notas atualizadas.

Para manter nomenclatura consistente, declare convenções no começo e siga-as: por exemplo, um padrão estável de operationId, nomes de tags apenas substantivos, nomes de schema no singular, um Error compartilhado e um nome de auth usado em todos os lugares.

Se você trabalha num ambiente tipo Koder.ai, é útil salvar o YAML como um arquivo real cedo e iterar em pequenos diffs. Assim você vê quais mudanças vieram de decisões aprovadas versus detalhes que o modelo chutou.

Valide o spec antes de compará-lo com a API em execução

Write OpenAPI from behavior
Turn endpoint behavior notes into a real OpenAPI file you can keep next to your code.

Antes de comparar com produção, garanta que o arquivo OpenAPI seja internamente consistente. Esse é o lugar mais rápido para pegar wishful thinking e linguagem vaga.

Leia cada endpoint como se você fosse o desenvolvedor cliente. Foque no que um chamador deve enviar e no que pode esperar receber.

Uma revisão prática:

  • Obrigatórios vs opcionais: marque campos obrigatórios corretamente e evite “tudo opcional”.
  • Tipos e formatos: seja explícito sobre UUIDs, emails, date-time, min/max.
  • Exemplos: adicione pelo menos um exemplo realista de request e response por endpoint, e mantenha exemplos alinhados com schemas.
  • Códigos de status: alinhe com suas behavior notes (create frequentemente é 201, não 200). Escolha 400 vs 422 e seja consistente.
  • Auth: declare o que é exigido por endpoint e se papéis afetam acesso.

Respostas de erro merecem cuidado extra. Escolha uma forma compartilhada e re-use-a. Alguns times mantêm muito simples ({ error: string }), outros usam um objeto ({ error: { code, message, details } }). Qualquer um pode funcionar, mas não misture entre endpoints e exemplos. Se misturar, o código cliente acumula casos especiais.

Um cenário de sanidade rápida ajuda. Se POST /tasks exige title, o schema deve marcá-lo como required, a resposta de falha deve mostrar o body de erro que você realmente retorna, e a operação deve esclarecer se auth é necessário.

Compare o spec com a implementação em execução

Quando o spec estiver como você pretende, trate a API em execução como a verdade sobre o que os clientes experimentam hoje. O objetivo não é “vencer” entre spec e código; é expor diferenças cedo e decidir claramente sobre cada uma.

Para um primeiro passe, amostras reais de request/response são a opção mais simples. Logs e testes automatizados também funcionam se forem confiáveis.

Fique de olho em incompatibilidades comuns: endpoints presentes em um lugar e não no outro, diferenças de nomes ou formatos de campo, diferenças de códigos de status (200 vs 201, 400 vs 422), comportamentos não documentados (paginação, ordenação, filtragem) e diferenças de auth (spec diz público, código exige token).

Exemplo: seu OpenAPI diz que POST /tasks retorna 201 com {id,title}. Você chama a API em execução e recebe 200 mais {id,title,createdAt}. Isso não é “quase igual” se você gera SDKs a partir do spec.

Antes de editar qualquer coisa, decida como resolver conflitos:

  • Se o comportamento está correto mas não documentado, corrija o spec.
  • Se o spec é o contrato acordado, corrija o código para coincidir.
  • Se nenhum dos dois estiver certo, ajuste o comportamento pretendido primeiro e depois atualize ambos.

Mantenha cada mudança pequena e revisável: um endpoint, uma resposta, um ajuste de schema. É mais fácil revisar e retestar.

Produza exemplos de validação cliente e servidor a partir do contrato

Quando você tiver um spec confiável, transforme-o em pequenos exemplos de validação. Isso é o que impede o drift de voltar.

Validação no servidor (rejeitar requisições inválidas)

No servidor, validação significa falhar rápido quando um request não bate com o contrato e retornar um erro claro. Isso protege seus dados e facilita achar bugs.

Uma forma simples de expressar exemplos de validação do servidor é escrevê-los como casos com três partes: input, output esperado e erro esperado (um código de erro ou padrão de mensagem, não texto exato).

Exemplo (contrato diz que title é obrigatório e tem 1 a 120 chars):

{
  "name": "Create task without title returns 400",
  "request": {"method": "POST", "path": "/tasks", "body": {"title": ""}},
  "expect": {"status": 400, "body": {"error": {"code": "VALIDATION_ERROR"}}}
}

Validação no cliente (detectar breaking changes cedo)

No cliente, validação é sobre detectar drift antes dos usuários. Se o servidor começar a devolver um formato diferente, ou um campo obrigatório desaparecer, seus testes devem sinalizar.

Mantenha checagens de cliente focadas no que você realmente precisa, como “uma task tem id, title, status.” Evite afirmar todo campo opcional ou ordem exata. Você quer falhas em mudanças breaking, não em adições inofensivas.

Algumas diretrizes para manter os testes legíveis:

  • Prefira checar presença e tipo em vez de valores exatos.
  • Assegure apenas campos obrigatórios, a menos que um opcional seja crítico.
  • Para erros, confira status e um código de erro, não mensagens completas.
  • Permita campos extras a menos que o contrato explicitamente os proíba.

Se você usa Koder.ai, pode gerar e manter esses casos de exemplo ao lado do arquivo OpenAPI, e atualizá-los como parte da mesma revisão quando o comportamento mudar.

Exemplo: uma Tasks API simples de ponta a ponta

Ship and test faster
Deploy and host your API alongside the app so teams can test the contract end to end.

Imagine uma API pequena com três endpoints: POST /tasks cria uma task, GET /tasks lista tasks e GET /tasks/{id} retorna uma task.

Comece escrevendo alguns exemplos concretos para um endpoint, como se estivesse explicando para um testador.

Para POST /tasks, o comportamento pretendido pode ser:

  • Sucesso: enviar { \"title\": \"Buy milk\" } e receber 201 com um objeto task novo, incluindo id, title e done:false.
  • Falha 1: enviar {} e receber 400 com um erro como { \"error\": \"title is required\" }.
  • Falha 2: enviar { \"title\": \"x\" } (muito curto) e receber 422 com { \"error\": \"title must be at least 3 characters\" }.

Quando o Claude Code rascunhar o OpenAPI, o trecho para esse endpoint deve capturar o schema, códigos de status e exemplos realistas:

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\" }

Uma incompatibilidade comum é sutil: a API em execução retorna 200 em vez de 201, ou retorna { \"taskId\": 123 } em vez de { \"id\": \"t_123\" }. Esse tipo de “quase igual” quebra clientes gerados.

Corrija escolhendo uma fonte de verdade. Se o comportamento pretendido está correto, altere a implementação para retornar 201 e a forma Task acordada. Se o comportamento de produção já é dependido, atualize o spec (e as behavior notes) para refletir a realidade, então adicione validação e respostas de erro faltantes para que os clientes não sejam surpreendidos.

Erros comuns que tornam um contrato desonesto

Um contrato vira desonesto quando deixa de descrever regras e começa a descrever o que sua API retornou em um bom dia. Um teste simples: uma nova implementação poderia passar por esse spec sem copiar as esquisitices de hoje?

Uma armadilha é o overfitting. Você captura uma resposta e transforma em lei. Ex.: sua API atualmente retorna dueDate: null para toda task, então o spec diz que o campo é sempre nullable. Mas a regra real pode ser “obrigatório quando status for scheduled.” O contrato deve expressar a regra, não apenas o dataset atual.

Erros são onde honestidade costuma quebrar. É tentador specar só respostas de sucesso porque parecem limpas. Mas clientes precisam do básico: 401 quando falta token, 403 para acesso proibido, 404 para IDs desconhecidos e um erro de validação consistente (400 ou 422).

Outros padrões problemáticos:

  • Nomes e tipos divergentes entre endpoints (taskId em uma rota, id em outra, ou priority string em uma resposta e number em outra).
  • Exemplos que contradizem schemas (valores de enum não batem, exemplos date-time não são ISO 8601).
  • Tipos alargados para evitar decisões (tudo vira string, tudo vira opcional).
  • O spec soa como marketing (“rápido”, “seguro”) em vez de ser testável.

Um bom contrato é testável. Se você não consegue escrever um teste que falhe a partir do spec, ele ainda não é honesto.

Checagens rápidas antes de compartilhar ou publicar o OpenAPI

Own the spec and code
Export source code and keep your OpenAPI and implementation together in your repo.

Antes de entregar o arquivo OpenAPI para outra equipe, faça uma revisão rápida: “alguém consegue usar isso sem ler sua mente?”.

Comece pelos exemplos. Um spec pode ser válido e ainda inútil se cada request e response for abstrato. Para cada operação, inclua pelo menos um exemplo realista de request e uma resposta de sucesso. Para erros, um exemplo por falha comum (auth, validação) geralmente basta.

Depois verifique consistência. Se um endpoint retorna { \"error\": \"...\" } e outro { \"message\": \"...\" }, clientes têm lógica ramificada por toda parte. Escolha uma única forma de erro e reutilize-a, junto com códigos de status previsíveis.

Um checklist curto:

  • Campos obrigatórios, formatos (email, uuid, date-time) e enums estão explícitos.
  • Códigos de status são intencionais e consistentes entre endpoints similares.
  • Respostas de erro incluem schema e exemplos, não só um status.
  • Você re-executou 2–3 chamadas reais por endpoint (tests, curl, Postman ou logs) e comparou payloads com o spec.
  • Você consegue escrever uma pequena chamada cliente a partir do spec sem adivinhar headers, nomes de campo ou nulabilidade.

Um truque prático: escolha um endpoint, finja que nunca viu a API e responda “o que eu envio, o que recebo de volta e o que quebra?” Se o OpenAPI não responder claramente, não está pronto.

Próximos passos: torne isso hábito (e mantenha mudanças seguras)

Esse fluxo paga dividendos quando roda regularmente, não só em um scramble de release. Adote uma regra simples e cumpra-a: rode sempre que um endpoint mudar e rode de novo antes de publicar um spec atualizado.

Mantenha propriedade simples. A pessoa que muda um endpoint atualiza as behavior notes e o rascunho do spec. Uma segunda pessoa revisa o diff “spec vs implementation” como uma code review. QA ou suporte costumam ser ótimos revisores porque enxergam respostas e edge cases pouco claros.

Trate edições de contrato como edições de código. Se você usa um construtor baseado em chat como Koder.ai, tirar um snapshot antes de mudanças arriscadas e usar rollback quando preciso mantém a iteração segura. Koder.ai também permite exportar código-fonte, facilitando manter spec e implementação lado a lado no repositório.

Uma rotina que costuma funcionar sem atrapalhar times:

  • Escreva behavior notes quando adicionar um endpoint
  • Valide o spec e rode testes de contrato antes de dar merge
  • Compare o spec com a API em execução antes do release
  • Faça snapshot antes de edições arriscadas; rollback se o diff ficar confuso

Próxima ação: escolha um endpoint existente. Escreva 5–10 linhas de behavior notes (inputs, outputs, casos de erro), gere um rascunho OpenAPI a partir dessas notas, valide, e compare com a implementação em execução. Corrija uma incompatibilidade, reteste e repita. Depois de um endpoint, o hábito tende a pegar.

Perguntas frequentes

O que significa “OpenAPI drift” em termos simples?

OpenAPI drift é quando a API que você realmente roda não corresponde mais ao arquivo OpenAPI compartilhado. O spec pode estar sem campos novos, códigos de status ou regras de autenticação, ou pode descrever um comportamento “ideal” que o servidor não segue.

Isso importa porque clientes (apps, outros serviços, SDKs gerados, testes) tomam decisões com base no contrato, não no que o servidor “geralmente” faz.

Quais são as formas mais comuns de drift afetarem times de cliente?

Os problemas para times de cliente aparecem de forma aleatória e difícil de depurar: um app móvel espera 201 mas recebe 200, um SDK não consegue desserializar uma resposta porque um campo foi renomeado, ou o tratamento de erros falha porque as formas de erro são diferentes.

Mesmo quando nada quebra imediatamente, as equipes perdem confiança e param de usar o spec, o que elimina seu sistema de alerta precoce.

Por que eu não deveria começar o spec OpenAPI copiando o código do backend?

Porque o código reflete o comportamento atual, incluindo esquisitices acidentais que você talvez não queira prometer a longo prazo.

Um padrão melhor é: escreva primeiro o comportamento pretendido (entradas, saídas, erros) e depois verifique se a implementação corresponde. Assim você tem um contrato que pode ser aplicado, em vez de um retrato do estado atual das rotas.

Qual é o mínimo de “behavior notes” que devo escrever por endpoint?

Para cada endpoint, capture:

  • Propósito: o que faz em uma frase
  • Auth: token/perfis necessários ou público
  • Request: query/path params, headers, e um exemplo de body JSON
  • Responses: pelo menos um exemplo de sucesso e um ou dois exemplos realistas de erro com códigos de status
  • Edge cases: IDs ausentes/inválidos, duplicatas (409?), resultados vazios, limites de paginação

Se você conseguir escrever uma requisição concreta e duas respostas, já dá para rascunhar um spec verdadeiro.

Como mantenho as respostas de erro consistentes em todo o spec?

Escolha uma forma de erro e reutilize em todo o spec.

Um padrão simples é:

  • { "error": "message" }, ou
  • { "error": { "code": "...", "message": "...", "details": ... } }

Depois use isso de forma consistente em endpoints e exemplos. Consistência importa mais que sofisticação, porque clientes vão codificar para esse formato.

Como eu faço prompting para o Claude Code sem que ele invente endpoints ou campos?

Dê ao Claude Code suas notas de comportamento e regras estritas, dizendo para não inventar campos. Um conjunto prático de instruções:

  • “Source of truth são as behavior notes. Não chute dados.”
  • “Se algo estiver incerto, adicione TODO no spec e liste em ASSUMPTIONS.”
  • “Inclua schemas reutilizáveis (como Error) e faça referências a eles.”
  • “Use nomenclatura consistente (PascalCase para schemas, lowerCamelCase para campos).”

Após a geração, revise a seção ASSUMPTIONS primeiro — é aí que a honestidade começa a se perder se você aceitar suposições.

O que devo checar no arquivo OpenAPI antes de compará-lo com a API em execução?

Valide o spec antes de comparar com produção:

  • Campos obrigatórios vs opcionais estão corretos
  • Formatos explícitos (UUID, email, ISO 8601 date-time)
  • Exemplos batem com schemas (enums, tipos, nulabilidade)
  • Códigos de status são intencionais e consistentes (ex.: create costuma ser 201)
  • Requisitos de auth por endpoint

Isso pega arquivos OpenAPI “wishful” antes mesmo de olhar o comportamento em produção.

Quando o spec e a API em execução discordam, qual devo mudar?

Trate a API em execução como o que os usuários veem hoje e decida caso a caso:

  • Se o comportamento está correto mas não documentado: atualize o spec
  • Se o spec é o contrato acordado: atualize o código
  • Se nenhum dos dois está certo: ajuste primeiro o comportamento pretendido e depois atualize ambos

Mantenha mudanças pequenas (um endpoint ou uma resposta por vez) para poder retestar rápido.

Como são checagens de contrato “server-side” vs “client-side”?

Validação no servidor significa rejeitar rapidamente requests que violem o contrato e retornar um erro claro e consistente (status + código de erro/shape). Isso protege dados e facilita achar bugs.

Validação no cliente significa detectar mudanças breaking antes dos usuários: verifique apenas no que você realmente depende:

  • Campos obrigatórios existem e têm o tipo esperado
  • Códigos de status batem com os fluxos esperados
  • Respostas de erro têm o formato acordado

Evite afirmar todos os campos opcionais para não quebrar testes por adições inocentes.

Qual é um hábito simples para evitar que o drift volte?

Uma rotina prática:

  • Atualize behavior notes e o spec sempre que um endpoint mudar
  • Valide o OpenAPI (schemas, exemplos, status codes, auth)
  • Compare alguns exemplos reais de request/response com o spec antes do release
  • Adicione pequenos testes de contrato para que o drift seja pego automaticamente

Se você usa Koder.ai, mantenha o OpenAPI junto com o código, faça snapshots antes de mudanças arriscadas e use rollback quando necessário.

Related posts