Prism, WireMock and MSW in a practical comparison
A mock server that is maintained by hand drifts away from the real API within weeks. Mock servers that work directly from the OpenAPI specification are always in sync, enabling frontend development without a backend dependency, QA tests without production infrastructure, and error scenarios at the push of a button.
Table of Contents
- 1. Why mock APIs from specs, not from fixtures
- 2. Prism: starting a mock server straight from OpenAPI
- 3. Prism in dynamic mode: fake data from the schema
- 4. WireMock: advanced mocks with state and sequences
- 5. MSW: mocking directly in the browser and Node.js
- 6. Simulating error scenarios on purpose
- 7. Integrating mock servers into CI pipelines
- 8. Prism vs. WireMock vs. MSW: head-to-head
- 9. Summary
- 10. FAQ
1. Why mock APIs from specs, not from fixtures
The classic approach to API mocking is a collection of static JSON files that the frontend reads in during development. That works for simple scenarios, but it has a systemic downside: the fixtures drift away from the real API. When the backend renames a field, changes a status code, or adds a new required field, the fixture files stay unchanged. The frontend is developed against stale data, and the team only notices during integration.
Mock servers that work directly from the OpenAPI specification solve this problem at its root. The specification is the single source of truth, and every change to it immediately affects the mock server. The frontend team automatically gets updated responses without having to maintain fixtures by hand. On top of that, a spec-based mock server can validate request data against the request schema and return an error on violations, catching frontend bugs before the backend is even finished.
2. Prism: starting a mock server straight from OpenAPI
Prism by Stoplight is the most widely used tool for spec-based API mocking. It reads an OpenAPI file and, within seconds, starts an HTTP server that answers every endpoint defined in it. The responses are assembled from the examples fields defined in the spec. In practice this means that whoever carefully maintains examples in the specification gets a mock server whose responses match the contract exactly.
Prism supports several operating modes. In the default mode it returns the first defined example. With the header Prefer: example=active_user, a frontend developer can request a specific example and so test different states defined in the spec. The --errors mode activates request validation: any request that does not match the schema is rejected with a 422 error instead of being let through. That is particularly valuable for frontend developers who want to make sure their request bodies conform to the spec.
# Install Prism globally
npm install -g @stoplight/prism-cli
# Start mock server from OpenAPI spec (static examples mode)
prism mock api/openapi.yaml --port 4010
# With request validation active (rejects invalid requests with 422)
prism mock api/openapi.yaml --port 4010 --errors
# Dynamic mode: generate fake data when no example is defined
prism mock api/openapi.yaml --port 4010 --dynamic
# Proxy mode: forward to real API, validate request/response against spec
prism proxy api/openapi.yaml http://api.example.com --port 4011 --errors
# Test specific example with Prefer header
curl -H "Prefer: example=active_user" http://localhost:4010/users/42
# Test 404 response
curl http://localhost:4010/users/99999
# Returns 404 with example from spec
# Run in Docker for CI (no global npm install needed)
docker run --rm -p 4010:4010 \
-v "$(pwd)/api/openapi.yaml:/tmp/spec.yaml" \
stoplight/prism:4 mock /tmp/spec.yaml --host 0.0.0.0
3. Prism in dynamic mode: fake data from the schema
In Prism's static example mode, the same responses come back every time, which is useful for deterministic tests but limited when building lists and pagination. Prism's dynamic mode generates random but schema-conformant data for every request. A string field gets a random string, an integer field a random number, an enum field one of the defined values. format hints such as email, date-time, and uuid are honored.
The result is a mock server that delivers realistic data on every request, enough to test layouts with real-world data lengths and to build list components against varying datasets. For more complex scenarios, such as stateful simulations or dependent data across endpoints, WireMock is the better choice. For pure schema conformance and fast bootstrapping, Prism is unmatched.
4. WireMock: advanced mocks with state and sequences
WireMock is a full HTTP stub server with a powerful configuration language for complex scenarios. Unlike Prism, which works purely from the spec, WireMock supports stateful mocks: an initial POST /orders creates an order, and a subsequent GET /orders/1 returns it, fully consistent. Sequence scenarios simulate APIs that return different states on repeated requests: the first GET /status returns pending, the second processing, the third completed.
WireMock can be bootstrapped from OpenAPI specifications, but its real strength lies in manually defined stub mappings. These mappings can be added and removed dynamically at runtime through the admin API, which is especially useful for test setups that need to switch between scenarios between tests. WireMock is the better choice over Prism for integration tests and complex QA scenarios, but it requires more configuration effort.
{
"mappings": [
{
"request": {
"method": "GET",
"urlPattern": "/users/[0-9]+"
},
"response": {
"status": 200,
"headers": { "Content-Type": "application/json" },
"jsonBody": {
"id": 42,
"email": "user@example.com",
"name": "Maria Mustermann",
"role": "editor",
"active": true,
"createdAt": "2025-01-15T10:30:00Z"
}
}
},
{
"scenarioName": "Order-Status-Flow",
"requiredScenarioState": "Started",
"request": { "method": "GET", "url": "/orders/1/status" },
"response": { "status": 200, "jsonBody": { "status": "pending" } },
"newScenarioState": "Processing"
},
{
"scenarioName": "Order-Status-Flow",
"requiredScenarioState": "Processing",
"request": { "method": "GET", "url": "/orders/1/status" },
"response": { "status": 200, "jsonBody": { "status": "completed" } }
}
]
}
5. MSW: mocking directly in the browser and Node.js
Mock Service Worker (MSW) takes a different approach than Prism and WireMock: it intercepts HTTP requests directly in the browser via a service worker, without spinning up a separate server. That means mock handlers are written in JavaScript and integrated directly into the frontend project. For React, Vue, or Svelte applications, MSW is often the more natural integration than an external mock server.
With the openapi-fetch library and MSW handlers generated from the OpenAPI spec, fully type-safe mocks can be produced. In the test environment (Jest, Vitest), the same handlers run in Node.js mode without a browser. MSW's decisive advantage: mock handlers and real API calls use the same code path, which makes it easier to switch between a mocked and a real backend without rewriting test code from scratch.
# Install MSW in a frontend project
npm install msw --save-dev
# Initialize Service Worker for browser mode
npx msw init public/ --save
# Generate MSW handlers from OpenAPI spec
npx openapi-msw generate \
--input api/openapi.yaml \
--output src/mocks/handlers.ts \
--typescript
# src/mocks/browser.ts - MSW browser setup
# import { setupWorker } from 'msw/browser'
# import { handlers } from './handlers'
# export const worker = setupWorker(...handlers)
# Start frontend dev server with mocks active
VITE_API_MOCKING=enabled npm run dev
# Run unit tests with MSW in Node mode (Jest/Vitest)
npm test -- --testPathPattern=api
# Generate TypeScript types from OpenAPI spec (keeps types in sync with mock)
npx openapi-typescript api/openapi.yaml -o src/api/schema.d.ts
6. Simulating error scenarios on purpose
A mock server that only returns successful responses only exercises the frontend's happy paths. Error scenarios are at least as important: what happens when the API returns 500? How does the frontend handle a 401 with an expired token? What does the UI show on a 429 rate limit? These scenarios need to be simulable on demand.
Prism enables error simulation via the Prefer header: Prefer: code=500 forces a 500 error regardless of which endpoint is hit. WireMock can simulate timeouts ("fixedDelayMilliseconds": 30000), network faults ("fault": "CONNECTION_RESET_BY_PEER"), and malformed responses ("fault": "MALFORMED_RESPONSE_CHUNK"), scenarios that are barely reproducible in manual testing. MSW handlers can encode any error response directly in JavaScript and switch between test cases.
7. Integrating mock servers into CI pipelines
Integrating mock servers into CI pipelines is essential for isolated, reproducible tests without external dependencies. The pattern: the mock server starts in the background, the test suite runs against it, the mock server shuts down. With Docker, mock servers are available in CI with no installation effort. The challenge lies in timing: the test must not start until the mock server is ready, and a wait-on check against the health endpoint solves that reliably.
Another CI use case: run Prism in --proxy mode in front of the real API server and enable request/response validation. Every contract violation, even when both backend and frontend appear to work, is reported as an error. That catches discrepancies between the implementation and the specification that would otherwise remain invisible without a validation layer. This approach is particularly valuable for teams that work code-first and generate the spec after the fact.
# .github/workflows/api-tests.yml - Prism mock server in CI
name: API Contract Tests
on: [push, pull_request]
jobs:
contract-tests:
runs-on: ubuntu-latest
services:
prism:
image: stoplight/prism:4
ports:
- 4010:4010
options: >-
--health-cmd "wget -q --spider http://localhost:4010/health || exit 1"
--health-interval 5s
--health-timeout 3s
--health-retries 10
steps:
- uses: actions/checkout@v4
- name: Copy spec to service
run: docker cp api/openapi.yaml prism:/tmp/spec.yaml
- name: Setup Node
uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- name: Wait for mock server
run: npx wait-on http://localhost:4010/health --timeout 30000
- name: Run contract tests against mock
run: npm test -- --testPathPattern=contract
env:
API_BASE_URL: http://localhost:4010
NODE_ENV: test
8. Prism vs. WireMock vs. MSW: head-to-head
All three tools solve the same underlying problem, eliminating API dependencies, but with different priorities and integration models. The choice depends on where the mock server needs to run and how complex the scenarios are.
| Criterion | Prism | WireMock | MSW |
|---|---|---|---|
| OpenAPI integration | Native, straight from spec | Possible via plugin | Via code generator |
| Setup effort | Minimal (1 command) | Medium (config files) | Medium (JS integration) |
| Stateful mocks | Not supported | Full support (scenarios) | Possible via JS logic |
| Browser integration | External server | External server | Service worker, native |
| Request validation | Built in (--errors) | Via extension | Via middleware |
In practice the tools complement each other: Prism for fast bootstrapping and spec-close mocks in development and CI, WireMock for complex integration tests with state management, MSW for unit tests and component tests directly inside the frontend project. Many teams use all three, in different parts of the test pyramid.
Mironsoft
API mocking, OpenAPI tooling, and CI integration
Want API mocking from OpenAPI set up for your team?
We set up Prism, WireMock, or MSW as a mock server from your OpenAPI specification, with error scenarios, schema validation, and CI integration for frontend and QA.
Mock server setup
Getting Prism or WireMock running from your OpenAPI spec
CI integration
Wiring a mock server into GitHub Actions, GitLab CI, or Jenkins
Error scenarios
Reproducibly simulating timeouts, 4xx/5xx, and network faults
9. Summary
API mocking from OpenAPI specifications is the modern alternative to manually maintained fixture files. Prism starts a spec-conformant mock server in seconds, with optional request validation and dynamic data generation. WireMock enables stateful scenarios, network fault simulation, and complex sequences for integration tests. MSW integrates mocking directly into the frontend project and enables type-safe handlers generated from the OpenAPI spec.
The common thread: all three tools eliminate manual mock-data maintenance and keep mocks automatically in sync with the specification. That means less time spent maintaining mocks, more confidence in the tests, and frontend development that no longer has to wait on backend completion.
API mocking from OpenAPI, the essentials at a glance
Prism
Native from the OpenAPI spec, 1 command, request validation with --errors, dynamic mode for fake data. Ideal for fast setup.
WireMock
Stateful scenarios, sequences, network fault simulation. Ideal for complex integration tests.
MSW
Service worker in the browser, no external server needed. Same code for browser and Node.js tests. Ideal for frontend unit tests.
CI integration
Start the mock server via Docker in CI, use wait-on to confirm readiness, run tests in isolation without an external API.