API mocking lets remote teams work in parallel without waiting for backend endpoints. The frontend team mocks the agreed API contract; the backend team implements against the same spec. When they integrate, surprises are minimal because the contract was validated throughout development.
WireMock (Java/Docker, Production-Grade)
WireMock is the most capable mock server for integration testing. It runs as a Docker container and supports request matching, response templating, stateful scenarios, and fault injection.
# docker-compose.yml
version: "3.8"
services:
wiremock:
image: wiremock/wiremock:3.x
container_name: wiremock
ports:
- "8080:8080"
volumes:
- ./wiremock/mappings:/home/wiremock/mappings
- ./wiremock/__files:/home/wiremock/__files
command: --verbose --global-response-templating
Define a stub in wiremock/mappings/users.json:
{
"mappings": [
{
"request": {
"method": "GET",
"urlPathPattern": "/api/users/[0-9]+"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"id": "{{request.pathSegments.[2]}}",
"name": "Test User",
"email": "user-{{request.pathSegments.[2]}}@example.com",
"plan": "pro",
"createdAt": "{{now format='yyyy-MM-dd'}}"
}
}
},
{
"request": {
"method": "POST",
"url": "/api/users",
"bodyPatterns": [
{
"matchesJsonPath": "$.email"
}
]
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json",
"Location": "/api/users/{{randomValue type='UUID'}}"
},
"jsonBody": {
"id": "{{randomValue type='UUID'}}",
"email": "{{jsonPath request.body '$.email'}}",
"createdAt": "{{now}}"
}
}
}
]
}
Test error scenarios with fault injection:
{
"request": {
"method": "GET",
"url": "/api/payment",
"headers": {
"X-Simulate-Error": { "equalTo": "timeout" }
}
},
"response": {
"fault": "CONNECTION_RESET_BY_PEER"
}
}
Mockoon (Desktop + CLI, Zero-Config)
Mockoon is the fastest way to spin up a mock API. Import an OpenAPI spec and it generates stubs automatically.
# Install CLI
npm install -g @mockoon/cli
# Start a mock environment from file
mockoon-cli start --data ./mockoon-environment.json --port 3001
# Start from OpenAPI spec
mockoon-cli start \
--data https://api.yourcompany.com/openapi.json \
--port 3001
Define environment rules in JSON (or use the desktop GUI and export):
{
"uuid": "abc123",
"name": "Payments API Mock",
"port": 3001,
"routes": [
{
"method": "post",
"endpoint": "payments/charge",
"responses": [
{
"statusCode": 200,
"label": "Successful charge",
"headers": [
{ "key": "Content-Type", "value": "application/json" }
],
"body": "{\n \"id\": \"ch_{{faker 'string.uuid'}}\",\n \"amount\": {{body 'amount'}},\n \"currency\": \"{{body 'currency'}}\",\n \"status\": \"succeeded\"\n}",
"rules": [],
"default": true
},
{
"statusCode": 402,
"label": "Card declined",
"body": "{\"error\": \"card_declined\", \"message\": \"Your card was declined.\"}",
"rules": [
{
"target": "body",
"modifier": "card_number",
"value": "4000000000000002",
"invert": false,
"operator": "equals"
}
],
"default": false
}
]
}
]
}
Docker Compose for shared team mock:
services:
api-mock:
image: mockoon/cli:latest
volumes:
- ./mockoon:/data
command: --data /data/environment.json --port 3001
ports:
- "3001:3001"
Prism (OpenAPI Contract Validation)
Prism by Stoplight serves mocks from OpenAPI specs and validates requests/responses against the schema. It catches contract violations at dev time.
npm install -g @stoplight/prism-cli
# Serve a mock from OpenAPI spec
prism mock https://api.yourcompany.com/openapi.yaml
# Or from a local file
prism mock ./api/openapi.yaml --port 4010
# Proxy real API but validate responses
prism proxy https://api.yourcompany.com ./api/openapi.yaml --port 4011
Prism returns errors when your OpenAPI spec and actual API diverge:
[PRISM] POST /payments/charge ✓ Request valid
[PRISM] POST /payments/charge ✗ Response invalid: missing required field 'transactionId'
Combine with CI to validate your API matches the spec on every deploy:
# .github/workflows/api-contract.yml
name: API Contract Tests
on: [push, pull_request]
jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Prism
run: npm install -g @stoplight/prism-cli
- name: Start API
run: docker-compose up -d api
- name: Validate responses against OpenAPI spec
run: |
prism proxy http://localhost:8080 ./api/openapi.yaml --port 4011 &
sleep 3
# Run integration test suite against Prism proxy
npm run test:integration -- --baseUrl http://localhost:4011
MSW (Mock Service Worker, Frontend-First)
MSW intercepts requests at the network level using a Service Worker in the browser or Node.js interceptors in tests. The same mock definitions work in both environments.
npm install msw --save-dev
npx msw init public/
Define handlers:
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users/:id', ({ params }) => {
return HttpResponse.json({
id: params.id,
name: 'Alice Test',
email: `user-${params.id}@example.com`,
});
}),
http.post('/api/payments/charge', async ({ request }) => {
const body = await request.json();
// Simulate card decline
if (body.cardNumber === '4000000000000002') {
return HttpResponse.json(
{ error: 'card_declined', message: 'Your card was declined.' },
{ status: 402 }
);
}
return HttpResponse.json({
id: `ch_${Math.random().toString(36).slice(2)}`,
amount: body.amount,
status: 'succeeded',
});
}),
];
Browser setup:
// src/mocks/browser.js
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
// src/main.jsx
if (process.env.NODE_ENV === 'development') {
const { worker } = await import('./mocks/browser');
await worker.start({ onUnhandledRequest: 'warn' });
}
Node.js test setup (Jest/Vitest):
// src/setupTests.js
import { server } from './mocks/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Override handlers per-test for error scenarios:
import { server } from '../mocks/server';
import { http, HttpResponse } from 'msw';
test('shows error message when payment fails', async () => {
server.use(
http.post('/api/payments/charge', () => {
return HttpResponse.json({ error: 'network_error' }, { status: 500 });
})
);
// ... render and assert
});
Tool Selection Guide
| Tool | Best For | Strength |
|---|---|---|
| WireMock | Integration/E2E testing | Advanced matching, fault simulation |
| Mockoon | Rapid prototyping, shared team mock | Zero config, GUI included |
| Prism | Contract validation | OpenAPI spec enforcement |
| MSW | Frontend development and unit tests | Network-level interception, no proxy |
For most remote teams: use MSW for frontend unit tests, Mockoon for shared team mocks during API development, and WireMock for integration test suites in CI.
Related Reading
- Best Tools for Remote Team API Documentation
- Best Tools for Remote Team Load Testing
-
Best API Key Management Workflow for Remote Development