How it works
The explanation, with examples you can run.
Only what is used
The idea comes from Ian Robinson's 2006 article: a provider's real obligations are the combined expectations of its current consumers, not every field it happens to return. A toy verifier makes the consequence clear:
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
Dropping a field nobody reads is safe, and the provider learns that without asking. The rename breaks exactly one consumer, and the failure names it.
The Pact flow
Pact is a widely used open-source tool for this, with libraries for most languages. On the consumer side, a unit test describes an interaction against a Pact mock server, and your real client code calls it:
import { Matchers, Pact } from "@pact-foundation/pact"import { getOrder } from "../src/orders-client"const { like } = Matchers const provider = new Pact({ consumer: "checkout-web", provider: "orders-api" }) test("reads an order's status", () => provider .addInteraction() .given("order 42 exists") .uponReceiving("a request for order 42") .withRequest("GET", "/orders/42", (b) => b.headers({ Accept: "application/json" })) .willRespondWith(200, (b) => b.jsonBody({ id: like(42), status: like("paid") })) .executeTest(async (mockServer) => { const order = await getOrder(mockServer.url, 42) expect(order.status).toBe("paid") }))like matches by type, so the contract says "a number" and "a string", not those exact values. A passing run writes a pact file, which CI publishes to a Pact Broker.
On the provider side, a verification test fetches the pacts, starts the real service, sets up each provider state through a handler you write ("order 42 exists" inserts that order), replays every request and compares the responses with what each consumer expects. The results go back to the broker.
Before deploying either side, the pipeline asks the broker:
pact-broker can-i-deploy --pacticipant checkout-web --version "$GIT_SHA" --to-environment production# ...deploy...pact-broker record-deployment --pacticipant checkout-web --version "$GIT_SHA" --environment productionWhat contracts don't do
A contract test checks the shape of the conversation, not the provider's business rules. Whether refunds are calculated correctly is the provider's own functional tests' job. Keep contracts minimal: put in a field only if the consumer really reads it, or the provider can't change anything. If a provider can't run consumer contracts, checking both sides against a shared OpenAPI schema is a weaker alternative.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.