Contratos Internos

Contract testing, consumer-driven contracts, Pact e design contract-first para garantir a compatibilidade entre serviços.

O que são contratos internos?

Em um sistema distribuído, cada serviço expõe interfaces que outros serviços consomem. Um contrato interno é o acordo — explícito ou implícito — sobre a forma, os tipos e a semântica dessas interfaces. Quando um serviço muda seu contrato sem coordenar com seus consumidores, as coisas quebram.

Os contratos internos formalizam essas dependências para que possam ser verificadas automaticamente, antes que uma mudança chegue à produção.

Contract Testing

O contract testing verifica se dois serviços (produtor e consumidor) estão de acordo quanto à forma da sua comunicação. Diferente dos testes de integração end-to-end, os contract tests são executados de forma independente em cada serviço.

Por que os testes de integração não bastam?

  • Os testes de integração exigem que todos os serviços estejam rodando simultaneamente
  • São lentos, frágeis e difíceis de manter
  • Não escalam quando você tem dezenas de serviços
  • Uma falha nem sempre indica claramente qual serviço quebrou o contrato

Como funciona o contract testing

  1. O consumidor define o que espera do produtor (o contrato)
  2. O contrato é verificado contra o produtor de forma independente
  3. Se o produtor cumpre o contrato, ambos os serviços são compatíveis
  4. Se não cumpre, o teste falha antes de chegar à produção

Consumer-Driven Contracts (CDC)

Na abordagem consumer-driven, são os consumidores que definem os contratos. Isso inverte a dinâmica tradicional em que o produtor define sua API e os consumidores se adaptam.

Fluxo de trabalho CDC

  1. O consumidor escreve um contrato: Define as interações que precisa — quais requests faz e quais respostas espera
  2. O contrato é compartilhado: É publicado em um broker ou repositório compartilhado
  3. O produtor verifica: Executa os contratos de todos os seus consumidores contra sua implementação
  4. Feedback rápido: Se uma mudança no produtor quebra algum contrato, o pipeline falha

Vantagens da abordagem CDC

  • Os produtores sabem exatamente o que seus consumidores usam
  • É possível fazer mudanças breaking com confiança — você sabe quem é afetado
  • Os consumidores definem apenas o que realmente precisam, não toda a API
  • Reduz o acoplamento — o produtor pode mudar o que ninguém usa

Pact

Pact é a ferramenta mais popular para consumer-driven contract testing. Suporta múltiplas linguagens (Java, JavaScript, Python, Go, .NET, Ruby) e oferece um fluxo completo.

Conceitos-chave do Pact

  • Pact file: Arquivo JSON que descreve as interações esperadas entre consumidor e produtor
  • Pact Broker: Serviço centralizado que armazena e gerencia os pact files
  • Can-I-Deploy: Ferramenta que verifica se é seguro fazer deploy de uma versão específica

Fluxo típico com Pact

Consumidor                    Pact Broker                    Produtor
    |                              |                              |
    |-- genera pact file --------->|                              |
    |                              |                              |
    |                              |<-- descarga pact files ------|
    |                              |                              |
    |                              |<-- publica resultados -------|
    |                              |                              |
    |-- can-i-deploy? ------------>|                              |
    |<-- sí/no -------------------|                              |

Exemplo de interação Pact

Do lado do consumidor, é definida a interação esperada:

Dado: que existe un producto con ID 123
Cuando: hago GET /api/products/123
Entonces: recibo status 200 con body { id: 123, name: "string", price: "number" }

Do lado do produtor, o Pact reproduz a interação contra a implementação real e verifica se a resposta corresponde.

Design Contract-First

Na abordagem contract-first, o contrato é definido antes de escrever qualquer código. Isso é especialmente útil quando várias equipes trabalham em paralelo.

Fluxo contract-first

  1. Definir o contrato: Usando OpenAPI, AsyncAPI, Protobuf ou outro formato de especificação
  2. Revisar e acordar: As equipes de produtor e consumidor revisam e aprovam o contrato
  3. Gerar código: Usar ferramentas de code generation para criar stubs, clientes e validadores
  4. Implementar: Cada equipe implementa sua parte de acordo com o contrato acordado
  5. Verificar: Contract tests automáticos validam que ambas as implementações cumprem o contrato

Ferramentas para contract-first

FerramentaTipoUso
OpenAPI / SwaggerREST APIsDefinição de endpoints, schemas e exemplos
AsyncAPIEvent-drivenDefinição de channels, mensagens e schemas
ProtobufgRPCDefinição de serviços e mensagens tipadas
JSON SchemaGeralValidação de estruturas de dados

Boas práticas

  • Comece com contract-first para APIs novas — é mais fácil do que fazer o retrofit de contratos depois
  • Use um Pact Broker (ou equivalente) para centralizar e versionar contratos
  • Integre contract tests no CI/CD — para que falhem antes de chegar ao staging
  • Não teste toda a API no contrato do consumidor — apenas o que você realmente usa
  • Versione os contratos junto com o código — um contrato é tão importante quanto o código que o implementa
  • Revise contratos no code review — uma mudança de contrato merece a mesma atenção que uma mudança de schema de banco de dados