O que são contratos de API? Definição, exemplos e melhores práticas
Toda falha de integração tem a mesma história de causa raiz. A Equipe A construiu um endpoint. A Equipe B o consumiu. Em algum ponto entre "o campo se chama userId" e "na verdade agora é user_id", algo quebrou em produção, e duas equipes passaram uma tarde em uma sala de guerra discutindo de quem era o entendimento correto da API.
A correção não é melhor comunicação. É um artefato melhor: um contrato de API. Uma definição única, formal e acordada do que a API faz, contra a qual ambos os lados podem construir, validar e cobrar um ao outro.
Este guia cobre o que são contratos de API, os formatos usados para diferentes estilos de API, o desenvolvimento contract-first versus code-first, como funciona o teste de contrato de API e as melhores práticas que mantêm os contratos confiáveis ao longo do tempo.
O que é um contrato de API?
Um contrato de API é a especificação formal e acordada da interface de uma API. Ele define, de forma precisa e inequívoca:
- Operações -- Os endpoints, métodos, queries ou procedimentos que a API expõe. Para uma API REST, são os paths e os verbos HTTP. Para gRPC, os serviços e RPCs. Para uma API orientada a eventos, os canais e tipos de mensagem.
- Schemas de requisição e resposta -- O formato exato dos dados trocados: nomes de campos, tipos, obrigatório vs opcional, formatos e restrições.
- Semântica de erros -- Como a falha se parece. Quais códigos de erro existem, o que significam e qual estrutura as respostas de erro seguem.
- Autenticação e autorização -- Como os chamadores se identificam: chaves de API, escopos OAuth, claims de JWT, mTLS.
- Regras de versionamento e estabilidade -- Quais partes da interface são estáveis, como as mudanças são introduzidas, como funciona a descontinuação e quais garantias (limites de taxa, SLAs) o provedor assume.
A palavra-chave é acordada. Um contrato não é apenas uma descrição do que o código por acaso faz hoje. É um compromisso entre um provedor e seus consumidores: "esta é a interface, e não vamos quebrá-la sem aviso." Esse compromisso é o que torna possível o desenvolvimento independente. A equipe de frontend pode construir contra o contrato enquanto o backend ainda está sendo escrito. Um parceiro pode integrar sem ler o seu código-fonte.
Se você já gerou um SDK de client a partir de um arquivo OpenAPI, simulou um serviço a partir de sua spec ou rejeitou um pull request porque ele quebrou um schema publicado, você usou um contrato de API como ele deve ser usado: como a fonte da verdade de uma interface.
Formatos de contrato de API: um por estilo de API
Não existe um formato de contrato universal, porque não existe um estilo de API universal. Cada família de protocolo convergiu para o seu próprio padrão de especificação.
OpenAPI para APIs REST / HTTP
O OpenAPI (antigo Swagger) é o formato de contrato dominante para APIs HTTP. Um documento OpenAPI descreve paths, operações, parâmetros, corpos de requisição, schemas de resposta, esquemas de autenticação e servidores -- tudo em YAML ou JSON.
paths:
/orders/{orderId}:
get:
summary: Get an order by ID
parameters:
- name: orderId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: The order
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
"404":
description: Order not found
O ecossistema em torno do OpenAPI é sua verdadeira força: visualizadores de documentação interativos, geradores de código de client e servidor, mock servers, validadores e linters consomem todos o mesmo arquivo.
Protocol Buffers para gRPC
APIs gRPC são definidas em arquivos .proto usando Protocol Buffers. O arquivo proto é o contrato -- ele define serviços, métodos RPC e mensagens fortemente tipadas, e tanto o código de client quanto o de servidor são gerados a partir dele.
service OrderService {
rpc GetOrder(GetOrderRequest) returns (Order);
}
message GetOrderRequest {
string order_id = 1;
}
Como a geração de código é obrigatória no gRPC, o drift de contrato entre a spec e a implementação é estruturalmente mais difícil do que no REST. Os campos numerados também codificam uma política de evolução explícita: você pode adicionar campos, mas renumerá-los ou reaproveitá-los quebra a compatibilidade.
GraphQL SDL para APIs GraphQL
O GraphQL tem o contrato embutido no próprio protocolo. A Schema Definition Language (SDL) descreve todo tipo, query, mutation e subscription que a API suporta, e o servidor a impõe: uma requisição que não corresponde ao schema é rejeitada antes que qualquer resolver rode. A introspecção significa que os consumidores sempre podem buscar o contrato atual a partir da API ao vivo.
AsyncAPI para APIs orientadas a eventos
APIs assíncronas -- tópicos Kafka, filas RabbitMQ, subjects NATS, WebSockets -- foram o velho oeste da documentação por anos. O AsyncAPI mudou isso ao adaptar a abordagem do OpenAPI para sistemas orientados a eventos. Um documento AsyncAPI descreve canais, as operações sobre eles (enviar/receber), os payloads de mensagem e os bindings de broker. Para arquiteturas em que "quem publica o quê, e quem consome?" é uma pergunta diária, um contrato AsyncAPI é a diferença entre uma resposta e um projeto de arqueologia.
Schemas de ferramentas MCP para agentes de IA
O tipo de contrato mais recente não descreve uma interface serviço-a-serviço de forma alguma. O Model Context Protocol (MCP) permite que serviços exponham ferramentas a agentes de IA, e cada ferramenta vem com um nome, uma descrição e um JSON Schema para suas entradas. Essa lista de ferramentas é um contrato de API genuíno -- possivelmente um de maior risco, porque define o que um agente autônomo tem permissão de fazer ao seu sistema. Escrevemos em profundidade sobre tratar ferramentas MCP como contratos de API e por que elas merecem o mesmo rigor de documentação que seus endpoints REST.
A conclusão: qualquer que seja o seu estilo de API, existe um formato de contrato legível por máquina para ele. Sistemas modernos geralmente precisam de vários ao mesmo tempo -- REST para a API pública, gRPC internamente, AsyncAPI para eventos, MCP para agentes -- e é exatamente por isso que os contratos se beneficiam de uma casa única em vez de cinco repositórios espalhados.
Desenvolvimento contract-first vs code-first
Existem duas formas pelas quais um contrato passa a existir, e a escolha molda todo o seu fluxo de trabalho de API.
Contract-first (design-first)
No desenvolvimento contract-first, você escreve a especificação antes de escrever qualquer implementação. O arquivo OpenAPI ou a definição proto é projetado, revisado e acordado -- e então tanto o provedor quanto os consumidores constroem contra ele, frequentemente em paralelo.
Vantagens:
- Desenvolvimento em paralelo. Os consumidores podem gerar clients e construir contra mocks enquanto o provedor implementa. Ninguém espera.
- Revisão de design antes da revisão de código. É muito mais barato discutir um nome de campo em um diff de YAML do que refatorar um endpoint já em produção.
- Consistência. Projetar contratos como artefatos deliberados torna natural impor convenções de nomenclatura, padrões de paginação e formatos de erro entre as APIs.
- Foco no consumidor. Você projeta a interface de que os consumidores precisam, não a interface que é mais fácil de pregar no seu modelo de dados existente.
Desvantagens:
- Mais processo de antemão. Para uma equipe de duas pessoas iterando em um endpoint interno, uma fase de design formal pode ser overhead.
- Risco de drift se a implementação não for validada contra o contrato -- você precisa de ferramentas (middleware de validação, checks de CI) para mantê-los honestos.
Code-first
No desenvolvimento code-first, você escreve a implementação e gera o contrato a partir dela -- anotações, reflection ou introspecção do framework produzem o documento OpenAPI ou o schema GraphQL.
Vantagens:
- Velocidade para equipes pequenas. Sem passo de design separado; o contrato é sempre derivável do código.
- Sem drift por construção. A spec gerada corresponde à implementação, porque vem da implementação.
Desvantagens:
- O contrato se torna um subproduto em vez de um compromisso. O que quer que o código faça é o que a API é -- incluindo as partes acidentais.
- Mudanças que quebram a compatibilidade passam facilmente, porque nada força uma revisão da interface como interface.
- Specs geradas costumam ser medíocres: descrições faltando, documentação de erro vaga, sem exemplos.
Qual você deveria usar?
Uma regra de bolso pragmática: quanto mais consumidores uma API tem, e quanto menos você os controla, mais o contract-first compensa. APIs públicas, integrações com parceiros e contratos entre equipes separadas merecem tratamento contract-first. Um endpoint interno consumido por um único frontend pertencente à mesma equipe pode ser code-first -- desde que o contrato gerado ainda seja publicado, versionado e checado quanto a mudanças que quebram a compatibilidade.
Muitas equipes maduras chegam a um híbrido: code-first pela velocidade, com gates de CI em nível de contrato (detecção de mudanças incompatíveis, linting de schema) que lhes dão a maior parte da segurança do contract-first.
Teste de contrato de API
Um contrato que nada verifica é um desejo. O teste de contrato de API é a prática de checar automaticamente que provedores e consumidores de fato estão em conformidade com a interface acordada. Três técnicas dominam.
Teste de contrato orientado pelo consumidor
No teste de contrato orientado pelo consumidor -- popularizado pelo Pact -- cada consumidor registra as interações específicas das quais depende: "quando eu faço GET em /orders/123, espero um 200 com um corpo contendo id, status e total". Essas expectativas registradas formam um contrato que é então reproduzido contra o provedor no pipeline de CI dele.
A força dessa abordagem é a precisão. O provedor aprende exatamente quais campos cada consumidor de fato usa. Quer remover um campo? Os testes de contrato te dizem imediatamente se algum consumidor vai quebrar -- antes de você implantar, não depois.
Validação de schema no CI
A técnica mais simples e mais ampla: validar que a implementação corresponde à spec publicada.
- Faça requisições contra o serviço e valide as respostas contra os schemas OpenAPI.
- Use middleware de validação que rejeita qualquer resposta que não esteja em conformidade com o contrato (ótimo em staging).
- Faça lint da própria spec quanto à completude e ao estilo (Spectral e ferramentas similares).
Isso pega o modo de falha mais comum -- a spec diz uma coisa, o código faz outra -- de forma barata e contínua.
Detecção de mudanças incompatíveis
Por fim, compare o próprio contrato. Ferramentas como oasdiff (OpenAPI), Buf (protobuf) e GraphQL Inspector comparam a nova versão de uma spec com a anterior e classificam cada mudança: aditiva (segura) ou incompatível (campo removido, tipo alterado, novo parâmetro obrigatório). Conecte isso ao CI e uma mudança incompatível se torna um build que falha e exige aprovação explícita e deliberada -- em vez de uma surpresa silenciosa para os seus consumidores.
Se você fizer apenas uma coisa desta seção, faça esta. A detecção de mudanças incompatíveis é barata de configurar e pega as falhas que mais doem.
Por que contratos de API pertencem à sua documentação de arquitetura
Aqui está a parte que a maioria das equipes deixa passar. Você pode ter belos arquivos OpenAPI, suítes Pact rigorosas e gates de mudanças incompatíveis no CI -- e ainda assim ser incapaz de responder à pergunta que importa quando algo precisa mudar: "quem depende deste contrato?"
Um arquivo de contrato em um repositório descreve uma interface, mas não diz nada sobre o seu contexto. Qual serviço o implementa? Quais serviços, frontends e parceiros o consomem? Se descontinuarmos este endpoint, o que de fato quebra? Esse conhecimento geralmente vive na cabeça das pessoas, o que significa que se degrada toda vez que alguém muda de equipe.
É aqui que documentação de arquitetura e contratos de API precisam um do outro:
- Um contrato sem contexto arquitetural desatualiza de forma invisível. Ninguém percebe o
openapi.yamlórfão descrevendo um serviço que foi reescrito no ano passado, porque nada o conecta ao sistema que ele descreve. - Um diagrama de arquitetura sem contratos é impreciso. Uma seta rotulada "REST/JSON" entre duas caixas te diz que uma relação existe, mas não o que flui por ela. O contrato é o que dá significado à seta.
O modelo C4 fornece a estrutura natural para essa conexão: contratos se anexam aos containers e components que os implementam e consomem (veja a entrada de modelo C4 no nosso glossário para uma revisão rápida desses termos). O container API Gateway carrega seu contrato OpenAPI. O microsserviço interno carrega seu arquivo proto. Os serviços centrados em Kafka carregam o documento AsyncAPI que define seus canais.
É exatamente assim que a funcionalidade de API Contracts da Archyl funciona: você importa contratos OpenAPI, gRPC, GraphQL, AsyncAPI ou MCP -- sincronizados do git ou colados diretamente -- e os vincula aos elementos C4 no seu modelo de arquitetura. Os vínculos são bidirecionais: a partir de um contrato você vê quais elementos o implementam e consomem, e a partir de qualquer elemento no diagrama você pode abrir as specs reais que descrevem suas interfaces. Quando um contrato muda, você consegue ver de relance quais partes da arquitetura estão no raio de impacto, em vez de reconstruir o quadro de dependências a partir de conhecimento tribal. Cobrimos a funcionalidade em detalhe em API Contracts: suas especificações de API, vinculadas à sua arquitetura.
O princípio se mantém independentemente da ferramenta: um contrato é mais valioso quando vive ao lado dos elementos arquiteturais que ele conecta, não em uma pasta que ninguém abre.
Melhores práticas para contratos de API: uma checklist
Um contrato é um compromisso de vida longa, então trate-o como tal:
- Estabeleça uma fonte única da verdade. Um local canônico por contrato. Se a spec existe em três lugares, ela existe em zero lugares. Seja um repositório git ou uma plataforma de arquitetura como a Archyl, todo mundo precisa saber onde vive a versão autoritativa.
- Versione explicitamente. Dê a todo contrato uma versão e defina o que um bump de versão significa. Versionamento semântico funciona bem: mudanças aditivas sobem a versão minor, mudanças incompatíveis sobem a major.
- Nunca quebre sem uma versão major. Remover um campo, mudar um tipo, adicionar um parâmetro obrigatório, apertar a validação -- tudo incompatível. Isso exige uma nova versão major ou um novo endpoint, mais um caminho de migração.
- Escreva uma política de descontinuação e a honre. Marque operações descontinuadas na spec, comunique uma data de desativação, dê aos consumidores uma janela realista (meses, não dias) e monitore o uso antes da remoção.
- Revise mudanças de contrato como mudanças de código. Um diff de schema merece ao menos tanto escrutínio quanto um diff de implementação -- ele tem mais consumidores.
- Automatize a imposição. Validação de schema e detecção de mudanças incompatíveis no CI. Os humanos concordam com o contrato; as máquinas o impõem.
- Documente erros e autenticação, não apenas o caminho feliz. Os 400s e 401s são onde os consumidores gastam o tempo de depuração. Especifique-os.
- Vincule contratos à sua arquitetura. Todo contrato deveria ser rastreável aos components que o implementam e aos que o consomem, para que a análise de impacto seja uma consulta, não uma investigação.
Perguntas frequentes
Qual é a diferença entre um contrato de API e documentação de API?
A documentação de API é escrita para humanos: guias, tutoriais, exemplos, explicações de conceitos. Um contrato de API é uma especificação formal e legível por máquina que tanto humanos quanto ferramentas consomem -- ele pode gerar código, validar requisições, guiar mocks e fazer builds de CI falharem. Uma boa documentação é frequentemente gerada a partir do contrato, mas o contrato é o artefato vinculante: a documentação descreve a API, o contrato a define.
O que é desenvolvimento contract-first?
O desenvolvimento contract-first (ou design-first) significa escrever e concordar com a especificação da API -- o documento OpenAPI, o arquivo proto ou o schema GraphQL -- antes de implementá-la. Consumidores e provedores então constroem em paralelo contra a mesma interface acordada. Ele antecipa a discussão de design, habilita o trabalho em paralelo e torna o contrato um compromisso deliberado em vez de um subproduto do código.
O que é teste de contrato de API?
O teste de contrato de API verifica automaticamente que provedores e consumidores estão em conformidade com a interface acordada. Ele inclui testes de contrato orientados pelo consumidor (estilo Pact, em que as expectativas do consumidor são reproduzidas contra o provedor), validação de schema no CI (checando se a implementação corresponde à spec) e detecção de mudanças incompatíveis (comparando versões da spec para sinalizar mudanças incompatíveis antes do release).
APIs internas também precisam de contratos?
Sim -- possivelmente mais, porque APIs internas mudam mais rápido e são protegidas por menos cerimônia. O contrato pode ser mais leve (geração code-first está ok), mas ainda deve ser publicado, versionado e checado quanto a mudanças incompatíveis. A maioria dos incidentes de produção causados por mudanças de API é causada por mudanças de API internas.
Pronto para dar aos seus contratos de API uma casa dentro da sua arquitetura? Explore a funcionalidade de API Contracts da Archyl -- contratos OpenAPI, gRPC, GraphQL, AsyncAPI e MCP, vinculados ao seu modelo C4. Ou continue lendo: API Contracts: suas especificações de API, vinculadas à sua arquitetura | Ferramentas MCP como contratos de API | O que é o modelo C4? Um guia completo.