Opinion

Contract testing without the tests

Last checked 2026-11-147 min read

Most teams that adopt consumer-driven contract testing never get every consumer to write and keep the tests: the cost lands on consumer teams, ownership is split, and every pair of teams has to coordinate. The OpenAPI spec you already have shows when a change removes or tightens something a client could depend on, with no test code from anyone. What it cannot show is who depends on it. Graphwake fills that gap with the smallest contract there is: each consumer team subscribes to the endpoints it calls, and a breaking change in the spec reaches only those teams, in Slack, Microsoft Teams or email. Keep contract tests where a runtime break is costly.

Exampleopenapi.yaml · before → after
− before+ after
/orders/{id}:  get:    parameters:      - name: currency        in: query        schema: { type: string }-       required: false+       required: true    responses:      "200":        description: OK        content:          application/json:            schema:              type: object              properties:                id: { type: string }-               total: { type: number }
  • BreakingNew required parameter currency
  • BreakingResponse field total removed
GET /orders/{id}reaches checkout and mobile-app
A removed response field is a breaking change. Graphwake tells the teams that subscribed to the endpoint.
On this page
  1. Why adoption stalls
  2. What the spec alone can tell you
  3. What the spec cannot tell you
  4. The smallest contract
  5. How Graphwake does it
  6. When contract testing alone is enough
  7. Using both
  8. Questions

Cross-team integrations break at the seams. Each service passes its own tests, and then the two stop agreeing. Contract testing is the usual answer, and most rollouts stall before every consumer has written its tests. We built Graphwake around a smaller ask: the OpenAPI spec you already publish, plus one subscription from each team that calls an endpoint. It catches the common breaking changes on every endpoint. It does not replace tests where behaviour matters.

Why adoption stalls

Pact describes itself as “a code-first tool for testing HTTP and message integrations using contract tests”, and its contract “is generated during the execution of the automated consumer tests” (docs.pact.io, as of 2026-11-14). That is where the cost comes from, and the people who pay it are not the people who change the API.

  • The consumer pays. A team that calls ten internal APIs is asked to write and keep contract tests for ten services it does not own, and each test only pays off when some other team changes something. That is hard to get into a sprint.
  • Ownership is split. The consumer writes the contract, the provider verifies it, and someone runs the broker. When a verification fails at 6 pm, it is not obvious whose job it is. Tests nobody owns rot, and a rotting contract test does real harm because it teaches people to ignore red.
  • Coordination costs the most. Every pair of teams has to agree on provider states, versions and the order of rollout. Pact’s own page on what it is good for lists “testing providers where the consumer and provider teams do not have good communication channels” as a poor fit. In a company with dozens of services, that can describe a fair share of the pairs.
  • Coverage stops at the first team that says no. Pact also lists an API whose other side “will not also be using Pact” as a poor fit. If the mobile team or a contractor team has no tests, the provider is back to guessing about the consumers it knows least about.

Pact’s docs warn that “in the wrong situation, it will probably be just as painful!” A company-wide rollout plan tends to assume every pair of teams is in the right situation.

Spec-driven tools such as Specmatic generate the tests from the provider’s spec instead (specmatic.io, as of 2026-11-14). The contract is then the provider’s description of the API; the spec by itself still does not say which teams rely on which part of it. Pact vs Specmatic compares the two approaches.

What the spec alone can tell you

If you publish an OpenAPI spec and keep it accurate, much of the contract is already written down. Compare the spec before and after a change, and the changes that can make an existing client fail show up without anyone writing a test:

  • An endpoint or a response field removed.
  • A required parameter or a required request field added.
  • A field’s type changed.
  • The accepted values narrowed, for example a shorter enum.

That covers the shape of most breaking changes between internal teams. The check runs on every pull request that touches the spec, and the consuming teams do not have to do anything for it.

What the spec cannot tell you

  • Behaviour. A total that switches from dollars to cents is the same number in the spec. You only see that by running the service.
  • Drift. If the spec and the code disagree, a spec check is checking the wrong thing. Generating the spec from the code in the build helps; it does not prove what the service returns.
  • What a consumer relies on beyond the spec. An undocumented field, the order of a list, or an error message someone parses with a regular expression. None of that is in the spec.
  • Who calls the endpoint. A spec check can say “total was removed from GET /orders/{id}”, but not which teams read total, or even which teams call GET /orders/{id}. So the finding goes to the pull request author, who usually does not know either.

The first three are reasons to keep contract tests where they earn their cost. The last one is why most breaking changes still surprise someone. The diff found the change, and the news went to the wrong person.

The smallest contract

A consumer-driven contract holds two kinds of information. Most of it is detail: the exact fields, values and states this consumer depends on. The rest is a single fact, that this team calls this endpoint. Only some integrations need the detail, which is expensive to write, while every integration needs the fact, and it costs almost nothing.

So in Graphwake we ask every consumer team for the fact and nothing more. A team that marks “we call GET /orders/{id}” has written the smallest contract there is: one subscription, with no test code and nothing to verify. Put that next to the spec diff and you get most of what teams wanted from contract testing. When the spec changes in a breaking way, the teams that call the endpoint hear about it, and with a CI step they hear while the change is still a pull request.

ExampleService graph · orders-api
GET/orders/{id}2 consumer teams
Service
orders-api
Owner
payments-team

Consumers

  • checkout · 4 peopleSlack #team-checkout
  • mobile-app · 6 peopleSlack #mobile-alerts

Suggested by Discovery

  • storefront · uses a neighbouring endpointmaybe · 72
GET/orders/{id}/invoiceBlind spot

No team subscribes to this endpoint. A breaking change here reaches no subscribed team.

Who owns an endpoint, who consumes it, and where nobody is listening. A suggested team is added only when someone confirms it.

You still want contract tests on the handful of integrations where a runtime break is expensive, or where consumers rely on behaviour the spec does not describe. Everywhere else, the spec plus a list of who calls what covers the common case for much less effort. It also covers every endpoint from the first day, and not only the ones whose consumers volunteered to write tests.

How Graphwake does it

  • Subscriptions are the contract

    Consumer teams subscribe to the endpoints they call. That is the whole ask: no test code, no broker, nothing to verify. Subscriptions are per endpoint, not per field.

  • Only the spec

    Graphwake reads your OpenAPI spec from a URL it checks every 30 minutes, or from one CI step on each pull request. It never asks for access to your code.

  • Breaking changes reach the subscribed teams

    A removed field, a new required parameter, a changed type or narrowed values reaches only the teams subscribed to that endpoint, in Slack, Microsoft Teams or email. Additions stay quiet by default.

  • Blind spots, scored

    Each change set gets an impact score from 0 to 100 with public rules. A breaking change on an endpoint nobody subscribes to counts as a blind spot, and rule-based Discovery suggests teams that may call it.

Good to know

When contract testing alone is enough

  • Both sides are controlled by teams that talk and are willing to write and keep the tests.
  • A runtime break would be costly: contract tests check the running service, without deploying everything first.
  • Consumers depend on behaviour or fields the spec does not describe, which consumer-driven contracts capture.
See who your next breaking change reaches.Paste a spec URL or add one CI step. 7-day free trial. Cancel before day 7 and you pay nothing.
Start free trial

Using both

The split we suggest is the spec and subscriptions on every endpoint, so every breaking change reaches the teams that call it, and contract tests on the integrations where a runtime break would be costly. If you already run Pact or Specmatic, keep them. The comparisons are in Pact vs Graphwake and Specmatic vs Graphwake. Routing models for the alert itself are in API breaking change alerts.

Questions

Is contract testing worth it?

Where consumers will write and keep the tests, and where a runtime break is costly, yes. Across dozens of internal teams it usually stalls on cost, ownership and coordination. A spec diff plus a list of which teams call each endpoint covers the common breaking changes on every endpoint, with no test code.

Why do contract testing rollouts stall?

Consumer-driven contracts ask each consumer team to write and keep tests for APIs it does not own, split ownership between consumer, provider and broker, and need every pair of teams to coordinate. Coverage ends at the first team that does not take part.

Can an OpenAPI spec replace contract tests?

For the shape of the API, largely: a spec diff finds removed fields and endpoints, new required inputs, type changes and narrowed values. It cannot see behaviour, drift between spec and code, or what a consumer relies on beyond the spec, and it does not know who calls the endpoint.

Does Graphwake replace Pact or Specmatic?

No. Graphwake reads the spec and tells the teams subscribed to a changed endpoint. Contract tests check a running service. They work side by side.

Pick an endpoint. See who it reaches. 7-day free trial. Cancel before day 7 and you pay nothing.

Start free trial

Sources and last verified

Sources checked on 2026-11-14.