Skip to content

Contract & API Testing Concepts

When to Use

Use contract tests when consumer and provider are maintained by separate teams and deploy independently. For same-repo services, integration tests at the HTTP layer are sufficient.

Decision

Approach What it verifies When to use
Schema validation (OpenAPI/JSON Schema) Response structure matches schema Any HTTP API; easy to add; does not test behavior
Consumer-driven contract (Pact) Consumer's actual usage pattern stays valid When consumer and provider are maintained by separate teams
Integration test against a test server Full request/response correctness When consumer and provider are in the same repo/team
E2E with real services Full system contract Pre-production smoke tests only; too slow for CI

Contract tests justify their cost when: - Different teams own consumer and provider - Provider deploys independently and could silently break consumers - The API surface is large with many optional/versioned fields

Pattern

// Consumer side: records what the consumer expects (Pact-style)
const interaction = {
  description: 'a request for user profile',
  request: { method: 'GET', path: '/users/123' },
  response: {
    status: 200,
    body: {
      id: 123,
      name: Matchers.string('Alice'),
      email: Matchers.string('alice@example.com'),
    },
  },
};
// Consumer test runs against a mock provider using this contract.
// Contract is published; provider runs it against its real implementation.

Simpler alternative: OpenAPI schema validation — generate/maintain an OpenAPI spec, run spectral lint in CI, use the spec to generate a mock server, and validate API responses against the schema in integration tests.

Common Mistakes

  • Wrong: E2E tests across services instead of contract tests → Right: Requires both services live; slow; brittle; hard to isolate failures
  • Wrong: Skipping contracts for "internal" APIs → Right: Internal APIs change and break consumers; contracts document the agreement
  • Wrong: Over-specifying the contract (exact field values) → Right: Use type matchers, not exact values, where possible
  • Wrong: No contract versioning strategy → Right: Breaking changes cause provider builds to fail without warning; version contracts

See Also