Contratos Internos
Contract testing, consumer-driven contracts, Pact y diseño contract-first para garantizar la compatibilidad entre servicios.
¿Qué son los contratos internos?
En un sistema distribuido, cada servicio expone interfaces que otros servicios consumen. Un contrato interno es el acuerdo — explícito o implícito — sobre la forma, tipos y semántica de esas interfaces. Cuando un servicio cambia su contrato sin coordinar con sus consumidores, las cosas se rompen.
Los contratos internos formalizan estas dependencias para que puedan ser verificadas automáticamente, antes de que un cambio llegue a producción.
Contract Testing
El contract testing verifica que dos servicios (productor y consumidor) están de acuerdo en la forma de su comunicación. A diferencia de los tests de integración end-to-end, los contract tests se ejecutan de forma independiente en cada servicio.
¿Por qué no alcanza con tests de integración?
- Los tests de integración requieren que todos los servicios estén corriendo simultáneamente
- Son lentos, frágiles y difíciles de mantener
- No escalan cuando tenés decenas de servicios
- Un fallo no siempre indica claramente qué servicio rompió el contrato
Cómo funciona el contract testing
- El consumidor define qué espera del productor (el contrato)
- El contrato se verifica contra el productor de forma independiente
- Si el productor cumple el contrato, ambos servicios son compatibles
- Si no lo cumple, el test falla antes de llegar a producción
Consumer-Driven Contracts (CDC)
En el enfoque consumer-driven, son los consumidores quienes definen los contratos. Esto invierte la dinámica tradicional donde el productor define su API y los consumidores se adaptan.
Flujo de trabajo CDC
- El consumidor escribe un contrato: Define las interacciones que necesita — qué requests hace y qué respuestas espera
- El contrato se comparte: Se publica en un broker o repositorio compartido
- El productor verifica: Ejecuta los contratos de todos sus consumidores contra su implementación
- Feedback rápido: Si un cambio en el productor rompe algún contrato, el pipeline falla
Ventajas del enfoque CDC
- Los productores saben exactamente qué usan sus consumidores
- Se pueden hacer cambios breaking con confianza — sabés a quién afecta
- Los consumidores solo definen lo que realmente necesitan, no toda la API
- Reduce el acoplamiento — el productor puede cambiar lo que nadie usa
Pact
Pact es la herramienta más popular para consumer-driven contract testing. Soporta múltiples lenguajes (Java, JavaScript, Python, Go, .NET, Ruby) y proporciona un flujo completo.
Conceptos clave de Pact
- Pact file: Archivo JSON que describe las interacciones esperadas entre consumidor y productor
- Pact Broker: Servicio centralizado que almacena y gestiona los pact files
- Can-I-Deploy: Herramienta que verifica si es seguro deployar una versión específica
Flujo típico con Pact
Consumidor Pact Broker Productor
| | |
|-- genera pact file --------->| |
| | |
| |<-- descarga pact files ------|
| | |
| |<-- publica resultados -------|
| | |
|-- can-i-deploy? ------------>| |
|<-- sí/no -------------------| |
Ejemplo de interacción Pact
Del lado del consumidor, se define la interacción 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" }
Del lado del productor, Pact reproduce la interacción contra la implementación real y verifica que la respuesta coincida.
Diseño Contract-First
En el enfoque contract-first, el contrato se define antes de escribir cualquier código. Esto es especialmente útil cuando múltiples equipos trabajan en paralelo.
Flujo contract-first
- Definir el contrato: Usando OpenAPI, AsyncAPI, Protobuf u otro formato de especificación
- Revisar y acordar: Los equipos de productor y consumidor revisan y aprueban el contrato
- Generar código: Usar herramientas de code generation para crear stubs, clientes y validadores
- Implementar: Cada equipo implementa su parte contra el contrato acordado
- Verificar: Contract tests automáticos validan que ambas implementaciones cumplen el contrato
Herramientas para contract-first
| Herramienta | Tipo | Uso |
|---|---|---|
| OpenAPI / Swagger | REST APIs | Definición de endpoints, schemas y ejemplos |
| AsyncAPI | Event-driven | Definición de channels, mensajes y schemas |
| Protobuf | gRPC | Definición de servicios y mensajes tipados |
| JSON Schema | General | Validación de estructuras de datos |
Buenas prácticas
- Empezá con contract-first para APIs nuevas — es más fácil que retrofitear contratos después
- Usá un Pact Broker (o equivalente) para centralizar y versionar contratos
- Integrá contract tests en CI/CD — que fallen antes de llegar a staging
- No testees toda la API en el contrato del consumidor — solo lo que realmente usás
- Versioná los contratos junto con el código — un contrato es tan importante como el código que lo implementa
- Revisá contratos en code review — un cambio de contrato merece la misma atención que un cambio de schema de base de datos