Skip to main content

API Contract Testing: Pact, OpenAPI & Consumer-Driven Guide

Contract testing lets consumer and provider services verify compatibility independently β€” no shared environment, no end-to-end flakiness. This guide covers consumer-driven contracts with Pact, OpenAPI schema validation with schemathesis, and pipeline integration.

βœ“ Pact consumer & provider setup βœ“ OpenAPI schemathesis testing βœ“ Pact Broker workflow βœ“ CI/CD pipeline integration

Contract Testing vs Integration Testing

Criteria Contract Testing (Pact) Integration Testing Schema Testing (OpenAPI)
Environment needed None (mock provider) Both services running Provider only
Speed Fast (unit-level) Slow Moderate
Who defines spec Consumer Shared Provider (OpenAPI)
Catches breaking changes Yes (per consumer) Yes Yes (spec drift)
Independent deploys Enabled Requires coordination Partial

Pact Consumer Test (Node.js / Jest)

The consumer defines the expected interaction. Pact spins up a mock provider, runs the consumer code against it, and saves the resulting contract as a JSON file:

// consumer.pact.test.ts
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import { getUserById } from '../api/usersClient';

const { like, string, integer } = MatchersV3;

const provider = new PactV3({
  consumer: 'orders-service',
  provider: 'users-service',
  port: 8080,
  dir: './pacts',  // contract files saved here
});

describe('Users Service contract', () => {
  it('returns a user by ID', async () => {
    await provider
      .given('user 42 exists')
      .uponReceiving('a request for user 42')
      .withRequest({
        method: 'GET',
        path: '/users/42',
        headers: { Authorization: like('Bearer token') },
      })
      .willRespondWith({
        status: 200,
        headers: { 'Content-Type': string('application/json') },
        body: {
          id: integer(42),
          name: string('Vic Chen'),
          email: string('[email protected]'),
        },
      })
      .executeTest(async (mockServer) => {
        const user = await getUserById(mockServer.url, '42');
        expect(user.id).toBe(42);
        expect(user.name).toBeDefined();
      });
  });
});
// After tests: ./pacts/orders-service-users-service.json is created

Pact Provider Verification

The provider loads contracts from the Pact Broker and verifies its real implementation satisfies every consumer's expectations:

// provider.pact.test.ts β€” run in the users-service CI pipeline
import { Verifier } from '@pact-foundation/pact';
import { app } from '../src/app';
import http from 'http';

describe('Pact Provider Verification', () => {
  let server: http.Server;
  let port: number;

  beforeAll(() => new Promise(resolve => {
    server = app.listen(0, () => {
      port = (server.address() as any).port;
      resolve(undefined);
    });
  }));

  afterAll(() => server.close());

  it('verifies all consumer contracts', async () => {
    await new Verifier({
      providerBaseUrl: `http://localhost:${port}`,
      pactBrokerUrl: process.env.PACT_BROKER_URL,
      pactBrokerToken: process.env.PACT_BROKER_TOKEN,
      provider: 'users-service',
      publishVerificationResult: true,
      providerVersion: process.env.GIT_SHA,
      // State handlers β€” set up test data per consumer scenario
      stateHandlers: {
        'user 42 exists': async () => {
          await db.users.upsert({ id: 42, name: 'Vic Chen', email: '[email protected]' });
        },
        'no users exist': async () => {
          await db.users.deleteAll();
        },
      },
    }).verifyProvider();
  });
});

OpenAPI Contract Testing with Schemathesis

Schemathesis generates hundreds of test cases from your OpenAPI spec and runs them against your live API, finding schema violations and crashes automatically:

# Install schemathesis
pip install schemathesis

# Test against a live staging API
schemathesis run https://staging-api.example.com/openapi.json \
  --checks all \
  --auth "Bearer $API_TOKEN" \
  --stateful=links \           # Follow OpenAPI link objects for stateful flows
  --max-examples=200 \         # Property-based test cases per endpoint
  --junit-xml=results.xml      # Output for CI

# Or test a local spec against a local server
schemathesis run ./openapi.yaml --url http://localhost:8080

# Example findings schemathesis catches:
# - 500 errors on valid inputs matching the spec
# - 200 responses with missing required fields
# - Accepting strings where the spec declares integer
# - Missing fields in error responses

# CI step in GitHub Actions
- name: API contract tests
  run: |
    schemathesis run $STAGING_URL/openapi.json \
      --auth "Bearer ${{ secrets.API_TOKEN }}" \
      --checks all \
      --junit-xml=schemathesis-results.xml
  continue-on-error: false
Share this tool: X / Twitter LinkedIn
βœ“ 60,000+ developers use DevPlaybook β˜…β˜…β˜…β˜…β˜… 4.8 / 5 on Gumroad βœ“ MIT licensed Β· Instant download βœ“ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

OpenAPI Validator API Response Mock Generator API Response Time Tester OpenAPI Schema Validator OpenAPI Mock Generator API Test Case Generator API Request Builder API Mock Server Config Generator Jest Testing Framework Guide API Rate Limit Calculator API Response Formatter & Analyzer HTTP API Tester LLM Cost Calculator AI Prompt Cost Calculator REST API Request Builder Vitest Guide β€” Vite-native Testing Cypress Frontend Testing Guide LLM Prompt Cost Calculator API Response Mocker AI Rate Limit Calculator API Key Generator AI Doc Generator β€” Pro Tool AI Unit Test Generator β€” Pro Tool Docker Compose Generator HTTP Methods Reference HTTP Code Snippet Generator HTTP Status Code Reference HTTP Status Code Reference Interview Question Generator JSON Diff Viewer JSON Diff Dockerfile Generator Rate Limiter Tester API Changelog Generator HTTP Mock Response Builder Rate Limit Calculator CORS Policy Builder Haproxy Config Validator HTTP Status Code Lookup HTTP Status Code Lookup Vue Component Generator HTTP Status Code Reference CI/CD Pipeline Generator LLM Context Window Calculator LLM Token Counter k6 Load Test Script Generator Playwright E2E Test Generator Prompt Token Estimator Playwright E2E Testing Guide Mock Service Worker (MSW) API Mocking Guide Pulumi Modern IaC Guide Kubernetes Resource Calculator HTML5 Canvas API Playground Prompt Injection Tester Token Context Calculator OpenAI Function Calling Generator Token Counter & Cost Estimator AI API Rate Limit Calculator

Related Articles

Mar 28, 2026 Β· 12 min read

Microservices vs Monolith in 2026: When to Choose What

The honest guide to choosing between microservices and monolithic architecture in 2026. Real tradeoffs, migration strategies, service mesh, event-driven patterns, and case studies from Netflix, Uber, and Shopify.

Mar 26, 2026 Β· 14 min read

Microservices vs Monolith: A 2026 Decision Framework

Stop debating, start deciding. A practical framework for choosing between microservices and monolith architecture in 2026β€”with real cost analysis, migration strategies, and a concrete decision flowchart.

Mar 26, 2026 Β· 16 min read

Microservices vs Monolith Architecture in 2026: Complete Decision Guide

Should you build a monolith or microservices? A practical 2026 guide covering pros/cons, migration strategies, real-world decision frameworks, and code examples with Docker Compose and Kubernetes.

Apr 2, 2026 Β· 10 min read

API Testing Best Practices 2026: Postman vs Insomnia vs Bruno

Complete guide to API testing in 2026. Compare Postman, Insomnia, and Bruno, learn best practices for REST and GraphQL testing, and build automation pipelines that catch regressions before production.

Apr 2, 2026 Β· 15 min read

DevOps Automation Tools in 2026: Orchestrating the Software Delivery Pipeline

Master DevOps automation with this guide to the tools that orchestrate modern software delivery. Covers CI/CD pipelines, infrastructure provisioning, configuration management, testing automation, and the emerging AI-assisted automation patterns that define 2026.

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚑ AI Code Review, Doc Generator & SQL Builder
  • ⚑ All premium templates & early access
  • ⚑ Member discounts on Gumroad products
Start Free Trial β†’

$9/mo after trial Β· Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products β€” grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro β€” $79 β†’

MIT licensed Β· Instant download Β· No subscription

See what's included β†’ Browse all deals β†’

Frequently Asked Questions

What is the difference between contract testing and integration testing?▼

Integration tests deploy both the consumer and provider together and test real interactions. They are slow, flaky, and require a shared environment. Contract tests decouple this: the consumer records its expectations (the contract) as a file, and the provider verifies it independently against its actual implementation without needing the consumer running. Contract tests are faster, more targeted, and enable independent deployments because each team can verify compatibility without orchestrating a shared test environment.

What is consumer-driven contract testing?▼

Consumer-driven contract testing means the consumer (the service making API calls) defines the contract β€” the minimum shape of requests and responses it needs. The provider then verifies that its implementation satisfies every consumer's contract. This approach prevents providers from breaking consumers they don't know about and gives providers a clear spec for what consumers actually use, rather than testing an assumed API surface.

What is Pact Broker?▼

Pact Broker is a central repository for storing, versioning, and sharing Pact contract files between consumer and provider teams. Without a broker, teams pass contract JSON files manually (via git or shared storage). The Pact Broker provides a UI for viewing compatibility matrices, webhooks to trigger provider verification when a new contract is published, 'can I deploy' queries to check if a version is safe to deploy, and network graphs of service dependencies.

What is the difference between Pact and schema-based contract testing?▼

Pact is consumer-driven: consumers generate contracts from real interactions in tests, capturing only what they actually use. Schema-based testing (OpenAPI + schemathesis/dredd) validates that the provider's actual responses conform to its declared OpenAPI specification. These approaches are complementary β€” schema testing catches spec drift from the provider's side, while Pact catches breaking changes from the consumer's perspective.

What is schemathesis?▼

Schemathesis is an OpenAPI contract testing tool that automatically generates test cases from your OpenAPI spec using property-based testing. It creates hundreds of valid and invalid inputs based on your schema definitions and runs them against your live API, looking for schema violations, 500 errors, crashes, and security issues like input that should be rejected but isn't. It is more thorough than hand-written tests because it explores edge cases you would not think to write manually.

How do I integrate contract testing into CI/CD?▼

For Pact: consumers run tests and publish contracts to Pact Broker on every PR. The Pact Broker triggers provider verification via webhook. Before deploying, both teams run pact-broker can-i-deploy to confirm compatibility. For OpenAPI: run schemathesis against the staging environment as a step in the provider's deployment pipeline. Gate deployments on test results. The goal is making it impossible to deploy a breaking change without knowing about it first.