OpenAPI é um formato para descrever uma API HTTP em um arquivo YAML ou JSON comum. Nele ficam listados os caminhos que a API expõe, os métodos que cada um aceita, os campos que seguem na requisição e o que a resposta devolve. O arquivo é legível tanto por pessoas quanto por programas, e é dessa mesma fonte que saem a documentação, as bibliotecas cliente e os simuladores usados em testes.
O nome formal é OpenAPI Specification, abreviado como OAS. Quem a mantém é a OpenAPI Initiative, um projeto de governança aberta sob a Linux Foundation.
A seguir: como o documento é montado, em que OpenAPI difere de Swagger, o que mudou nas versões 3.1 e 3.2 e por que a promessa central do formato — documentação que nunca fica desatualizada — não se cumpre sozinha.
Como é um documento OpenAPI
Um arquivo que funciona é mais curto do que a maioria imagina:
openapi: 3.1.0
info:
title: Links
version: "1.0"
paths:
/links:
post:
summary: Criar link curto
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [url]
properties:
url:
type: string
format: uri
responses:
'201':
description: Link criado
Só dois campos de nível superior são obrigatórios, openapi e info, e o documento precisa conter pelo menos um entre paths, components e webhooks. É assim que a especificação OAS 3.1.1 define.
Já nessas primeiras linhas mora uma armadilha: openapi e info.version são coisas diferentes. O primeiro é a versão do próprio formato, que as ferramentas leem para saber como interpretar o documento. O segundo é a versão da sua API. A especificação diz isso de forma explícita, mas a intuição sugere o contrário — e é assim que surgem arquivos declarando openapi: 1.0.
Especificações maiores costumam ser divididas em vários arquivos com $ref: o documento raiz aponta para ./paths/links.yaml, que aponta para ./schemas/link.yaml. É prático e gera um problema ao qual volto no final.
OpenAPI e Swagger não são a mesma coisa
É a confusão mais comum do assunto.
| O que é | Quem mantém | |
|---|---|---|
| OpenAPI | o padrão, o formato em si | OpenAPI Initiative, Linux Foundation |
| Swagger | um conjunto de ferramentas que leem esse formato | SmartBear |
A história explica a bagunça. No começo, Swagger designava ao mesmo tempo a especificação e as ferramentas. Depois a especificação passou para a OpenAPI Initiative e virou OpenAPI Specification, enquanto o nome Swagger ficou com as ferramentas — Swagger UI, Swagger Editor e as demais.
Na prática, "nós usamos Swagger" quase sempre significa "temos um arquivo OpenAPI e o exibimos com o Swagger UI". Nada prende uma coisa à outra: o mesmo arquivo abre igualmente bem no Redoc, no Scalar ou em um gerador de clientes.
Versões: 3.0, 3.1 e 3.2
As diferenças entre os ramos não são cosméticas.
3.0 continua sendo a mais difundida. Seu ponto fraco são os esquemas de dados: parecem JSON Schema sem serem totalmente compatíveis com ele, o que atrapalha a interoperabilidade entre ferramentas repetidamente.
3.1 fechou essa lacuna. O objeto Schema passou a ser um superconjunto do JSON Schema Draft 2020-12, então os esquemas que você já mantém em JSON Schema podem ser reaproveitados em vez de reescritos. A revisão atual, 3.1.1, foi publicada em 24 de outubro de 2024.
3.2 chegou em setembro de 2025. Pelo anúncio da OpenAPI Initiative, o que mais se destaca:
- o método HTTP
query, para leituras idempotentes cujos parâmetros não cabem na URL; additionalOperations, para métodos fora do padrão;- tipos de mídia em streaming: Server-Sent Events, JSON Lines, sequências JSON;
- tags hierárquicas, com
summary,parentekind; - fluxo de dispositivo do OAuth 2.0, para aparelhos com entrada desconfortável.
Vale escolher a versão que suas ferramentas realmente suportam, e não o número mais alto. O suporte a 3.1 no ecossistema é sólido; a 3.2 é mais recente e parte das ferramentas ainda está se adaptando. Nossa própria especificação declara 3.1.0.
O que a especificação entrega na prática
Um único arquivo resolve várias coisas ao mesmo tempo:
- documentação interativa — Swagger UI ou Redoc montam a página direto do arquivo, com formulário para testar requisições;
- bibliotecas cliente — geradores produzem um SDK na sua linguagem, dispensando invólucros escritos à mão;
- simuladores — um servidor simulado sobe a partir da descrição antes de o backend existir, e o front não fica parado;
- testes de contrato — os testes comparam respostas reais com os esquemas e flagram o momento em que uma resposta deixa de bater com a descrição.
É dessa lista que sai o principal argumento a favor do OpenAPI: a documentação deixa de ser um texto à parte que alguém esquece de atualizar.
O argumento está correto. Ele só não se executa sozinho.
Nada liga a especificação ao código
Esta é a parte que os textos de "o que é OpenAPI" quase nunca mencionam, e a que morde em produção.
O arquivo de especificação é só um arquivo. O roteador não sabe que ele existe. O controlador também não. Você pode apagar um endpoint, acrescentar outro ou transformar um campo obrigatório em opcional — e nenhum teste vai falhar. A documentação não se sincroniza sozinha: ela continua correta exatamente enquanto alguém lembrar de editá-la.
O desencontro acontece nos dois sentidos, e cada um prejudica de um jeito:
- documentado, mas não funciona. A pessoa lê a documentação, envia a requisição e recebe um 404. A confiança no resto da documentação desaba na hora — se aqui mentiram, onde mais?
- funciona, mas não está documentado. Para quem procura, o recurso simplesmente não existe. Ninguém encontra, ninguém paga por ele.
O segundo caso é o mais perigoso, porque ninguém reclama. Nem há quem reclame: o usuário não sabe que aquele endpoint está lá.
Foi exatamente o que aconteceu conosco. A API da Lix.li tinha três endpoints de conversões funcionando — uma listagem de eventos mais o recebimento de postbacks, individual e em lote — e nenhum deles aparecia na especificação. O código rodava, os testes passavam, e enquanto isso a página da API exibia dois caminhos completamente diferentes que não existiam no código. Isso apareceu em uma conferência geral, não por um relato de erro.
Como detectar o desencontro automaticamente
Não se resolve com disciplina, e sim com um teste. A ideia é direta: pegar a lista de caminhos da especificação, pegar a lista de rotas do roteador e comparar os dois conjuntos nos dois sentidos.
caminhos do openapi.yaml → existe essa rota? → se não, a documentação mente
rotas do roteador → o caminho está descrito? → se não, o recurso é invisível
A metade "o que está documentado funciona" se verifica melhor com uma requisição real: chamar o endpoint sem credenciais e conferir que a resposta é 401, e não 404. A distinção importa. 401 quer dizer que a rota foi encontrada e pede chave; 404, que não existe esse caminho. Nada é gravado no processo, porque a autenticação roda antes do controlador.
A verificação inversa lê a configuração de rotas. Ela ainda obriga a listar as exceções de forma explícita — endpoints internos que não têm lugar em um contrato público. Essa lista já vale por si: faz você decidir uma vez, deliberadamente, o que considera a sua API pública.
Escrevemos esse teste depois do episódio das conversões. Ele se justificou de imediato: se as conversões forem removidas da especificação de novo, o teste falha e nomeia os dois caminhos ausentes.
Duas armadilhas que se descobrem tarde
$ref e caminhos relativos. Quando a especificação está dividida em arquivos, as referências internas são resolvidas em relação à URL de onde o arquivo foi servido. Um documento raiz disponível em /openapi vai procurar ./paths/links.yaml em /paths/links.yaml e não encontrar nada. No navegador tudo parece certo, porque o Swagger UI carrega o arquivo do local real dele — mas um gerador de clientes apontado para o mesmo documento vai tropeçar. Ou você serve a especificação apenas do diretório dela, ou a empacota em um arquivo único sem $ref externos.
O Swagger UI é vazio para um rastreador. Uma página de Swagger UI são poucas linhas de marcação mais um script que desenha o conteúdo no navegador. No HTML de origem não há um único caminho de endpoint. Para quem lê, a página está boa; para indexação, está em branco. Some a isso um erro frequente no robots.txt: uma regra Disallow: /api/, escrita para esconder os endpoints JSON, esconde junto a documentação para humanos que mora no mesmo prefixo. O certo é bloquear o caminho exato com a versão — /api/1.0/, por exemplo — e não a seção inteira.
Por onde começar
Se a API já existe e a descrição não, a ordem é mais ou menos esta:
- Descreva um endpoint à mão. Isso basta para entender a estrutura.
- Escolha a versão que suas ferramentas suportam com folga; por padrão, a 3.1.
- Divida o arquivo com
$refquando ele deixar de caber em uma tela, e defina na hora de qual URL ele é servido. - Coloque um teste que compare a especificação com o roteador nos dois sentidos. Antes desse passo, qualquer afirmação sobre documentação em dia é promessa, não propriedade.
Para ver como isso fica em uma API real, a documentação da API da Lix.li cobre links, grupos, testes A/B e conversões. O serviço construído em volta dessa API está na página da API de encurtamento de links. Em temas vizinhos ficam o que são webhooks, a análise dos redirecionamentos 301, 302, 307 e 308 e o SDK de PHP para integrar por código.