Home » OpenAPI e JSON Schema: o que cada contrato valida em uma API

OpenAPI e JSON Schema: o que cada contrato valida em uma API

por Redação
0 comentários
Ilustração editorial de uma interface HTTP ligada a documentos estruturados e validadores de dados.

OpenAPI e JSON Schema não são dois nomes para o mesmo contrato. OpenAPI descreve a interface de uma API HTTP: caminhos, operações, parâmetros, autenticação, respostas e conteúdo. JSON Schema descreve a forma dos dados: tipos, propriedades, campos obrigatórios, formatos e combinações aceitas.

As tecnologias se encontram porque uma operação HTTP costuma receber e devolver JSON. Nesse ponto, um documento OpenAPI usa estruturas compatíveis com JSON Schema para detalhar o corpo da requisição ou da resposta. A separação ajuda a decidir qual ferramenta deve documentar, validar ou gerar cada parte da integração.

O que OpenAPI descreve

A OpenAPI Specification define um formato legível por pessoas e ferramentas para representar uma interface HTTP. Um documento pode informar que `POST /pedidos` exige autenticação, aceita determinado corpo, devolve `201` quando cria o recurso e responde com erros conhecidos em outras situações.

Esse conjunto sustenta documentação interativa, geração de clientes, mocks, testes de contrato e validação no gateway ou na aplicação. OpenAPI também registra servidores, parâmetros de caminho e consulta, headers, mídia aceita e mecanismos de segurança.

O foco é a operação completa. Saber que um campo `total` é numérico não informa em qual URL ele aparece, qual método envia o dado, qual status indica sucesso ou qual credencial é exigida. Essas partes pertencem ao contrato da API.

O que JSON Schema valida

O projeto JSON Schema define uma linguagem para anotar e validar documentos JSON. Um schema pode exigir que `id` seja uma string, impedir propriedades desconhecidas, limitar um número a valores positivos e determinar que pelo menos um entre dois campos esteja presente.

O mesmo schema pode ser útil fora de uma API HTTP. Arquivos de configuração, mensagens em filas, eventos, documentos armazenados e parâmetros de ferramentas também podem seguir JSON Schema. Ele não precisa conhecer URL, método, status ou autenticação para verificar a estrutura do dado.

Essa independência permite compartilhar modelos entre diferentes interfaces, desde que a equipe controle versão e compatibilidade. Também evita forçar detalhes de transporte em um contrato que deveria representar apenas conteúdo.

Onde os dois se complementam

Em uma API de cadastro, OpenAPI pode definir `POST /clientes`, o header de autenticação, o tipo de mídia e os códigos de resposta. O schema associado ao corpo determina se `nome` é obrigatório, se `email` segue um formato e se `dataNascimento` aceita nulo.

Na resposta, a operação informa que o status `201` devolve JSON; o schema descreve os campos do cliente criado. Ferramentas conseguem combinar essas informações para exibir documentação e verificar exemplos.

O cuidado é observar a versão suportada. OpenAPI e JSON Schema evoluíram, e algumas versões de OpenAPI usam subconjuntos ou regras próprias. Um validador precisa ser compatível com a versão declarada no documento, não apenas reconhecer a sintaxe básica.

Validação não substitui teste de comportamento

Um payload pode obedecer ao schema e ainda produzir resultado errado. JSON Schema verifica estrutura e restrições declaradas; não confirma que o serviço calculou imposto corretamente, persistiu a transação ou respeitou autorização. OpenAPI pode descrever respostas, mas não prova que a implementação segue o documento.

Por isso, contratos devem entrar em testes automatizados. O guia sobre APIs e testes automatizados mostra como checar compatibilidade durante a evolução. Para serviços internos, contratos e versionamento ajudam a controlar mudanças entre consumidores e provedores.

Um contrato sem duplicação

A implementação mais previsível mantém uma fonte principal para cada definição. Caminhos, operações, status e segurança ficam no documento OpenAPI. Estruturas reutilizáveis ficam em schemas nomeados e referenciados pelas operações. Código gerado ou validações derivadas não devem virar uma segunda definição editada manualmente.

Ao revisar OpenAPI e JSON Schema, a equipe precisa confirmar quatro pontos: a versão de cada especificação, o local canônico dos schemas, a validação executada no pipeline e os testes de comportamento que cobrem regras fora do alcance estrutural. Essa divisão reduz divergência entre documentação, validação e implementação.

A versão declarada muda o significado do schema

A versão do documento OpenAPI não é detalhe de cabeçalho. Na especificação 3.0, o objeto Schema foi inspirado em JSON Schema, mas não implementava integralmente um draft moderno. OpenAPI 3.1 alinhou essa área ao JSON Schema Draft 2020-12. A versão OpenAPI 3.2.1 mantém um dialeto próprio que inclui os vocabulários do Draft 2020-12 e palavras adicionais da OAS.

Isso afeta validadores e geradores. Uma ferramenta que entende apenas OpenAPI 3.0 pode rejeitar palavras válidas em 3.1 ou 3.2, interpretar `nullable` de forma diferente ou perder construções como tipos que incluem `null`. Trocar somente o número da versão sem verificar o ecossistema pode deixar documentação, gateway, geração de clientes e testes com leituras divergentes.

Em OpenAPI 3.2.1, `jsonSchemaDialect` pode indicar o dialeto padrão para os schemas do documento, enquanto `$schema` pode selecionar um dialeto em um schema específico. Quando esses campos não aparecem, valem as regras definidas pela própria versão da OAS. A equipe deve registrar qual combinação é suportada por seus validadores, e não presumir que toda ferramenta que lê YAML acompanha a mesma semântica.

Um exemplo de contrato HTTP

Considere uma operação de criação de pedido:

openapi: 3.2.1
info:
  title: Pedidos
  version: 1.0.0
paths:
  /pedidos:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NovoPedido'
      responses:
        '201':
          description: Pedido criado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pedido'
        '422':
          description: Dados válidos na estrutura, mas recusados pelo negócio

OpenAPI associa método, caminho, mídia e respostas. Os schemas referenciados descrevem os documentos. `NovoPedido` pode exigir itens e endereço; `Pedido` pode acrescentar identificador e estado. O status `422` registra uma possibilidade do protocolo, mas seu schema não consegue provar sozinho quando o estoque ou a política comercial devem causar a recusa.

Um JSON Schema útil precisa ser explícito

Um schema mínimo para os dados pode ser:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://exemplo.com/schemas/novo-pedido.json",
  "type": "object",
  "required": ["clienteId", "itens"],
  "properties": {
    "clienteId": { "type": "string", "minLength": 1 },
    "itens": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["sku", "quantidade"],
        "properties": {
          "sku": { "type": "string" },
          "quantidade": { "type": "integer", "minimum": 1 }
        },
        "additionalProperties": false
      }
    }
  },
  "additionalProperties": false
}

`$schema` identifica o dialeto; `$id` dá uma identidade estável para resolução de referências. `required` é necessário porque declarar uma propriedade não a torna obrigatória. `additionalProperties: false` é necessário se campos desconhecidos devem ser rejeitados; `properties` sozinho não faz isso. Esses detalhes estão na documentação do JSON Schema e evitam validadores permissivos por acidente.

O uso de `format` também requer cuidado. Palavras como `email`, `date-time` e `uri` podem funcionar como anotação ou como asserção, dependendo do dialeto e da configuração do validador. Quando a regra precisa bloquear uma entrada, a equipe deve testar o comportamento concreto da biblioteca adotada.

O que cada camada consegue validar

Um validador JSON Schema pode confirmar tipos, limites, padrões, presença de campos e relações expressas por palavras como `oneOf`, `anyOf`, `if`, `then` e `else`. Ele não conhece automaticamente banco de dados, identidade do usuário ou disponibilidade de estoque. Também não sabe se um identificador pertence ao cliente autenticado sem receber essa lógica da aplicação.

Uma ferramenta OpenAPI pode confirmar se o caminho existe, se o método aceita aquele tipo de mídia, se parâmetros obrigatórios foram enviados e se o corpo segue o schema associado. Ela pode verificar que a resposta `201` está documentada, mas não que a implementação escolheu o status correto para cada regra de negócio.

Testes de comportamento completam o conjunto. Eles criam cenários, chamam a aplicação e confirmam efeitos: autorização, idempotência, persistência, eventos publicados e cálculo. Um contrato estrutural reduz entradas e saídas inesperadas; não substitui a especificação do negócio.

Reutilização sem transformar tudo em um único modelo

Referências evitam copiar a mesma estrutura em várias operações. Um schema `Endereco` pode ser usado em pedido e cliente; respostas de erro podem compartilhar um formato. Ainda assim, reutilização excessiva cria acoplamento. O objeto que entra em `POST /clientes` não precisa ser idêntico ao que sai em uma consulta administrativa.

Modelos de leitura, criação e atualização costumam ter requisitos diferentes. Em uma atualização parcial, ausência pode significar “não alterar”, enquanto `null` pode significar “limpar”. Se todos usam o mesmo schema, campos somente de leitura podem aparecer em requisições e propriedades obrigatórias podem impedir operações válidas.

OpenAPI dispõe de composição e referências, mas a clareza deve prevalecer. Schemas menores, nomeados pelo papel na operação, tornam compatibilidade mais fácil de revisar. Componentes comuns devem representar conceitos realmente comuns, não apenas objetos que hoje têm campos parecidos.

Compatibilidade precisa de política

Adicionar campo opcional costuma ser compatível para consumidores tolerantes, mas quebra clientes que rejeitam propriedades desconhecidas. Tornar campo obrigatório, restringir enum ou mudar tipo tende a ser incompatível. Remover uma resposta documentada pode quebrar tratamento de erro, mesmo que o schema principal continue igual.

Por isso, a análise precisa considerar produtor e consumidor. Em requisições, ampliar o que o servidor aceita é diferente de ampliar o que um cliente envia. Em respostas, acrescentar dados é diferente de exigir dados novos na entrada. Ferramentas de diff ajudam, mas a classificação final depende da direção do fluxo e das promessas públicas da API.

Uma política simples define versão canônica, regra para mudanças incompatíveis, janela de depreciação e responsáveis pelos consumidores. O documento deve ser validado no pipeline, e exemplos precisam obedecer aos próprios schemas. Se há geração de cliente, o artefato gerado deve ser testado contra uma instância ou mock compatível.

Erros recorrentes na prática

Um erro comum é manter OpenAPI para documentação e modelos separados no código, editando ambos manualmente. Eles se afastam até que o portal aceite um corpo e o servidor exija outro. Outro é publicar exemplos que não validam, o que faz a documentação ensinar uma chamada inválida.

Também é frequente usar JSON Schema sem declarar draft, copiar palavras de uma versão diferente ou escolher uma biblioteca pelo nome sem verificar suporte. Em OpenAPI, misturar `nullable`, união com `null` e ferramentas de versões distintas cria resultados inconsistentes. A correção começa por inventariar versões e executar casos válidos e inválidos no mesmo validador usado em produção.

Validação somente na borda também não garante eventos internos. Se a API transforma uma requisição em mensagem, o schema do evento precisa de ciclo de vida próprio. Ele pode reutilizar definições, mas deve representar as garantias reais do canal e dos consumidores.

Geração, mocks e validação em execução

Gerar cliente a partir de OpenAPI reduz código repetitivo e aproxima tipos do contrato, mas o resultado continua dependente do gerador e da versão da linguagem. Uma mudança de template pode alterar nomes, tratamento de nulos ou serialização mesmo quando o documento permanece igual. Por isso, clientes gerados devem ser versionados ou reproduzíveis, compilados no pipeline e cobertos por uma chamada representativa.

Mocks permitem que consumidores trabalhem antes da implementação completa. Para serem úteis, precisam produzir exemplos que validem e incluir respostas de erro, campos opcionais e limites. Um mock que devolve sempre o cenário ideal ajuda na interface inicial, mas não demonstra comportamento diante de autorização negada, paginação, idempotência ou indisponibilidade.

Na aplicação, a validação pode ocorrer na entrada, na saída ou em um proxy. Validar entrada impede que dados estruturalmente inválidos cheguem ao negócio. Validar saída detecta divergência da implementação, porém requer cuidado para não expor ao cliente um erro interno com conteúdo sensível. Em alto volume, custo e observabilidade também precisam ser medidos antes de validar todo payload em produção.

Gateways conseguem aplicar parte do contrato, mas não conhecem invariantes internas. A configuração deve deixar claro se um schema apenas documenta, gera código ou bloqueia tráfego. Misturar essas funções sem registrar o ponto de execução cria uma falsa sensação de cobertura. O pipeline deve testar o mesmo documento e dialeto carregados pelo componente que realmente toma a decisão.

Checklist para um contrato verificável

Um contrato confiável de OpenAPI e JSON Schema deve declarar versões e dialetos, manter uma fonte canônica, validar exemplos, rejeitar casos inválidos conhecidos e passar por análise de compatibilidade no pipeline. Operações precisam documentar autenticação, parâmetros, mídia, status e erros; schemas precisam declarar tipos, obrigatoriedade, propriedades extras, nulos e limites de forma intencional.

Além disso, testes devem confirmar que a implementação segue o documento e que regras de negócio produzem os efeitos esperados. Clientes e mocks gerados entram na mesma verificação. Com essa divisão, OpenAPI descreve a conversa HTTP, JSON Schema restringe os documentos trocados e testes demonstram comportamento. Cada camada assume um problema distinto, o que torna a API mais previsível sem duplicar definições.

Você também pode gostar