API Contract Testing With OpenAPI: Validate Your APIs Against the Spec Automatically
Your OpenAPI/Swagger spec says the endpoint returns 200 with a user object. Your actual API returns 200 with a completely different shape. Contract testing catches this mismatch automatically.
🎠Want to master this with real projects? Join the Playwright Automation Mastery course at The Testing Academy.
Contents
What API Contract Testing Validates
- Response shape matches OpenAPI schema (fields, types, required)
- Status codes match documented responses (200, 400, 404, 500)
- Request validation — API rejects invalid requests per spec
- Header contracts — Content-Type, auth headers as documented
Playwright + OpenAPI Validation
import Ajv from 'ajv';
import { readFileSync } from 'fs';
import yaml from 'js-yaml';
const spec = yaml.load(readFileSync('openapi.yaml', 'utf-8')) as any;
const ajv = new Ajv({ allErrors: true });
function getSchema(path: string, method: string, status: number) {
return spec.paths[path]?.[method]?.responses?.[status]?.content?.['application/json']?.schema;
}
test('GET /users matches OpenAPI spec', async ({ request }) => {
const response = await request.get('/api/users');
const body = await response.json();
const schema = getSchema('/users', 'get', 200);
const validate = ajv.compile(schema);
const valid = validate(body);
expect(valid, JSON.stringify(validate.errors)).toBe(true);
});
test('POST /users validates request body', async ({ request }) => {
// Send invalid request (missing required field)
const response = await request.post('/api/users', {
data: { name: 'Test' } // Missing required 'email'
});
expect(response.status()).toBe(400);
const error = await response.json();
expect(error.message).toContain('email');
});
🚀 Level Up Your Playwright
From locators to CI pipelines — build a production-grade Playwright + TypeScript framework step by step.
Consumer-Driven vs Provider-Driven
| Approach | Who Defines Contract | Tool |
|---|---|---|
| Provider-driven | API team publishes OpenAPI spec | Ajv + OpenAPI |
| Consumer-driven | Consumer defines what they need | Pact |
| Bi-directional | Both sides verify | PactFlow |
CI Pipeline for Contract Tests
name: API Contract Tests
on:
pull_request:
paths: ['openapi.yaml', 'src/api/**']
jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test tests/contracts/
- name: Validate OpenAPI spec
run: npx @redocly/cli lint openapi.yaml
🎓 Master Playwright End to End
Join hundreds of SDETs building real automation frameworks. Lifetime access, hands-on projects, and a job-ready portfolio.
