REST API Contract Testing and Mocking
Frontend and backend teams often build at the same time. The frontend waits for endpoints, and the backend waits for feedback. One team changes a field name, and the other team's app breaks in production. Contracts and mocks fix both problems by agreeing on the API shape first.
The Blueprint Picture
Builders and electricians work from one blueprint. The electrician installs outlets where the plan says, even before the walls exist. Inspectors compare the finished house against the same plan. An API contract plays that blueprint role for software teams.
What a Contract Contains
An OpenAPI file lists the paths, methods, request fields, response fields, types, and status codes. Both teams treat it as the source of truth.
paths:
/books/{id}:
get:
responses:
"200":
description: One book
content:
application/json:
schema:
type: object
required: [id, title, price]
properties:
id: { type: string }
title: { type: string }
price: { type: integer }
Mock Servers
A mock server reads the contract and answers requests with sample data. Frontend developers start building screens on day one, with no backend ready.
Frontend App ──→ Mock Server (built from contract) ──→ sample JSON Later: Frontend App ──→ Real Backend ──→ real JSON
Mocks also simulate rare situations that are hard to trigger on a real server, such as a 503 error, a slow response, or an empty list.
Mock Response Examples
| Scenario | Mock Behavior |
|---|---|
| Happy path | 200 with a complete book |
| Not found | 404 with the standard error body |
| Server failure | 503 to test retry logic |
| Slow network | Response delayed by 5 seconds |
Contract Testing
Contract tests prove that the real API still matches the agreed shape. The test calls an endpoint and compares the response against the schema. Any extra, missing, or mistyped field fails the test.
CI pipeline │ ├─ start the backend ├─ call each endpoint with sample data ├─ validate responses against the OpenAPI schema └─ fail the build on any mismatch
Teams run these tests on every code change, so a broken contract never reaches users.
Consumer-Driven Contracts
In this approach, each client team records exactly which fields and behaviors it relies on. The backend team runs those recorded expectations as tests. Pact is a popular tool for this style.
Frontend team ── writes expectations ──→ contract file
Backend CI ── replays expectations against the real API
pass: safe to release fail: tell the frontend team
The backend learns about breaking changes before release. Fields that no client uses can leave safely, and fields that clients depend on stay protected.
Spec First or Code First
| Approach | Process | Strength |
|---|---|---|
| Spec first | Write the contract, then build both sides | Teams work in parallel |
| Code first | Write code, then generate the contract | Documentation always matches code |
Both styles work when automated checks keep the file and the code in sync.
Catching Breaking Changes Automatically
Diff tools compare two versions of a contract and report removed fields, changed types, and new required inputs. Run the diff in code review. A reviewer sees at a glance whether a change will break clients.
Good Practices
- Store the contract in version control beside the code.
- Review contract changes like code changes.
- Include error responses in the contract, not just success cases.
- Keep mock data realistic, with believable names, dates, and amounts.
Common Mistakes
Outdated Contracts
A contract that nobody updates misleads everyone. Automated checks keep it honest.
Mocks That Hide Problems
Mocks that always succeed give false confidence. Include failures and edge cases.
Testing Only Success Paths
Clients meet errors in production. Test 4xx and 5xx responses against the contract.
