In this lesson, you will learn how to use Pact to establish an automated "contract" between your services, ensuring that API changes don't break downstream consumers.
The Problem with Integration Tests
When working in a microservices ecosystem, traditional end-to-end integration tests often become bottlenecks. They are slow, brittle, and require both the consumer and provider services to be running simultaneously in a shared environment. If the provider changes a field name or an object structure, you might not find out until the deployment fails.
Enter Pact: Consumer-Driven Contracts
Pact changes the perspective: the consumer defines the expectations of the API they need, and the provider verifies that their implementation meets those exact expectations.
Instead of hitting a live server, the consumer runs tests against a "Mock Service" provided by Pact. This interaction is recorded as a JSON "pact file." This file acts as the contract.
// Consumer-side test (using @pact-foundation/pact)
const provider = new Pact({ consumer: 'OrderService', provider: 'ProductService' });
await provider.addInteraction({
state: 'a product with ID 101 exists',
uponReceiving: 'a request for product 101',
withRequest: { method: 'GET', path: '/products/101' },
willRespondWith: {
status: 200,
body: { id: 101, name: 'T-Shirt', price: 20 }
}
});
Verification and Feedback
Once the consumer test passes, the resulting pact file is shared with the Provider team (typically via a Pact Broker). The Provider then runs a verification task: Pact replays the requests defined in the contract against the Provider’s actual codebase. If the Provider code returns a different response body or status code than the contract requires, the test fails.
This ensures that the Provider cannot introduce a breaking change without the Consumer being alerted before the code ever reaches production. By decoupling the testing process from live infrastructure, you gain the ability to deploy services independently with high confidence.
Key Takeaway: Consumer-driven contracts shift the focus from testing the whole system to verifying the agreement between services, allowing you to catch breaking changes at build time rather than runtime.