Traditional contract testing points downstream: the provider publishes a schema; consumers check their compliance. Consumer-driven contracts invert the direction. Each consumer publishes an executable statement of what it sends and reads — endpoints, fields, formats — and the provider replays those expectations against its real implementation on every build. A change that breaks any consumer fails in the provider’s pipeline, minutes after the commit.
The inversion yields a second dividend: together the contracts map the interface surface in actual use — a field no contract mentions is demonstrably dead.
How It Works
- Each consumer writes its expectations as executable examples: the request it sends, the response elements it reads.
- Consumers publish these contracts to a shared broker, versioned per consumer and per environment.
- The provider’s CI fetches all current contracts and replays them against the real provider implementation.
- A failed expectation blocks the provider’s release and names the consumer it would break.
- A deployment gate asks the broker which versions are verified against each other before promoting either side.
Failure Modes
- An over-specified contract encodes fields the consumer never reads: provider changes fail the gate for data nobody uses.
- Stale contracts from a retired consumer block provider releases until someone prunes them from the broker.
- Contracts verify structure, not semantics: a provider passes every contract yet returns wrong values, and the gate stays green.
Verification
- Provider CI verifies 100% of current consumer contracts on every commit; a red verification blocks promotion.
- The broker’s compatibility matrix answers “can this version deploy?” for both sides before every release.
- Integration defects that escape to staging or production trend toward zero; each escape gains a retroactive contract.
Variants and Related Tactics
- Provider-driven contracts (schema-first) — the provider publishes, consumers comply; simpler, but breakage surfaces on the consumer side and later.
- Tolerant Reader — consumer-side tolerance shrinks what contracts must pin down; the two combine well.
- Schema registry with compatibility rules — checks producer changes against evolution rules instead of real consumer expectations; cheaper, coarser.
Example
The checkout team consumes the pricing service’s quote endpoint and reads net, tax, and total. Its contract states: given a valid product id, the response contains those three numeric fields. When the pricing team renames tax to taxes, checkout’s contract fails pricing’s build within minutes — before anything deploys. The same week, pricing deletes the rounding_mode field without ceremony: no contract ever mentioned it.
References
- Consumer-Driven Contracts: A Service Evolution Pattern — Ian Robinson, martinfowler.com, 2006
- ContractTest — Martin Fowler, bliki, 2011
- Building Microservices, 2nd ed. — Sam Newman, O’Reilly, 2021 — chapter 9 treats contract tests and consumer-driven contracts in depth