Prism: Spin Up a Mock Server from Your OpenAPI Spec
API-first development means writing your OpenAPI specification before writing code. But there's a gap between having a spec and having something to develop against — until you write the API, frontend developers are blocked.
Prism closes this gap. Give it an OpenAPI (Swagger) specification and it instantly runs a mock server that serves responses matching your spec. No configuration. No code. Just a spec and a running API.
What Is Prism?
Prism is an open-source HTTP mock server and contract validator built by Stoplight. It reads OpenAPI 2.0 and 3.x specifications and provides two primary functions:
Mocking: Serve responses that conform to your spec using examples and schemas defined in the spec.
Validation: Act as a proxy between clients and real servers, validating that requests and responses match the spec.
Installation
npm install -g @stoplight/prism-cliOr run without installing:
npx @stoplight/prism-cli mock openapi.yamlDocker:
docker run --rm -it stoplight/prism mock -h 0.0.0.0 openapi.yamlBasic Usage
Given an OpenAPI spec, start a mock server:
prism mock openapi.yamlPrism starts listening on port 4010 by default and logs the available endpoints:
[1:23:45 PM] › [CLI] … awaiting Starting Prism…
[1:23:45 PM] › [CLI] ✔ success GET http://127.0.0.1:4010/users
[1:23:45 PM] › [CLI] ✔ success POST http://127.0.0.1:4010/users
[1:23:45 PM] › [CLI] ✔ success GET http://127.0.0.1:4010/users/{id}
[1:23:45 PM] › [CLI] ✔ success DELETE http://127.0.0.1:4010/users/{id}Immediately, you can call these endpoints and get responses shaped by your spec.
Understanding Response Generation
Prism generates responses using a priority order:
- Static examples defined in the spec (highest priority)
- Schema-based dynamic generation using the response schema and JSON Schema Faker
- Empty response if no schema or example exists
Static examples
Define examples in your OpenAPI spec:
# openapi.yaml
paths:
/users/{id}:
get:
summary: Get a user
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: User found
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
alice:
value:
id: 1
name: Alice Johnson
email: alice@example.com
createdAt: '2024-01-15T10:30:00Z'
'404':
description: User not found
content:
application/json:
example:
error: User not found
code: USER_NOT_FOUNDPrism returns the alice example for GET /users/1.
Dynamic response generation
Without explicit examples, Prism generates responses from the schema:
components:
schemas:
User:
type: object
required:
- id
- name
- email
properties:
id:
type: integer
format: int64
name:
type: string
minLength: 1
email:
type: string
format: email
createdAt:
type: string
format: date-timePrism generates a valid User object with plausible values for each property based on the type and format.
Requesting dynamic responses
Force dynamic generation with the Prefer header:
curl http://localhost:4010/users/1 \
-H "Prefer: dynamic=true"Each request returns different auto-generated data. Useful for testing your frontend with varied inputs.
Contract Validation
This is where Prism becomes more than a simple mock tool. In proxy mode, it validates that real API traffic conforms to your spec:
prism proxy openapi.yaml https://api.yourservice.comNow http://localhost:4010 is a validating proxy. All requests to Prism are forwarded to https://api.yourservice.com, and Prism validates both the request and response against your spec.
Request validation
Prism checks incoming requests for:
- Required parameters (path, query, header, body)
- Parameter types matching the spec
- Body matching the request schema
- Valid enum values
If a request fails validation, Prism returns a 400 response with details:
{
"type": "https://stoplight.io/prism/errors#UNPROCESSABLE_ENTITY",
"title": "Invalid request",
"status": 422,
"detail": "Your request is not valid and no HTTP validation response was found in the spec, so Prism is generating this error for you.",
"validation": [
{
"location": ["body", "email"],
"severity": "Error",
"message": "must match format \"email\""
}
]
}Response validation
When acting as a proxy, Prism validates API responses against the spec and logs warnings when responses don't conform:
[2:15:30 PM] › [PROXY] ⚠ warning Response for GET /users has an invalid body: response body must be arrayThis catches cases where your implementation diverges from the spec — useful as a continuous contract check.
Validation-only mode (without proxying)
prism mock openapi.yaml --validate-requestIn this mode, invalid requests get spec-driven error responses, but Prism still serves mock data for valid requests.
Error Response Mocking
Use HTTP status codes to trigger specific responses in Prism:
# Trigger 404 response
curl http://localhost:4010/users/999 \
-H <span class="hljs-string">"Prefer: code=404"
<span class="hljs-comment"># Trigger 500 response
curl http://localhost:4010/users/1 \
-H <span class="hljs-string">"Prefer: code=500"This requires that your spec defines responses for those status codes. If it does, Prism serves the spec's error response.
Your spec should define error responses explicitly:
responses:
'404':
description: User not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: NOT_FOUND
message: The requested user does not exist
'422':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
'500':
description: Server error
content:
application/json:
example:
code: INTERNAL_ERROR
message: An unexpected error occurredSelecting Between Multiple Examples
If your spec has multiple examples for an endpoint, select by name:
curl http://localhost:4010/users \
-H "Prefer: example=empty-list"Given this spec:
responses:
'200':
content:
application/json:
examples:
with-users:
value:
- id: 1
name: Alice
empty-list:
value: []The Prefer: example=empty-list header returns the empty array example.
CI/CD Integration
GitHub Actions
name: API Contract Tests
on: [push, pull_request]
jobs:
contract-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Prism
run: npm install -g @stoplight/prism-cli
- name: Start mock server
run: prism mock openapi.yaml &
- name: Wait for server
run: npx wait-on http://localhost:4010
- name: Run API tests
run: npm run test:apiTesting against Prism mock
Write tests that hit the Prism mock server:
// api.test.js
const axios = require('axios')
const client = axios.create({ baseURL: 'http://localhost:4010' })
describe('Users API contract', () => {
test('GET /users returns an array', async () => {
const response = await client.get('/users')
expect(response.status).toBe(200)
expect(Array.isArray(response.data)).toBe(true)
})
test('GET /users/:id returns user shape', async () => {
const response = await client.get('/users/1')
expect(response.status).toBe(200)
expect(response.data).toMatchObject({
id: expect.any(Number),
name: expect.any(String),
email: expect.any(String),
})
})
test('GET /users/:id 404 error shape', async () => {
try {
await client.get('/users/999', {
headers: { 'Prefer': 'code=404' }
})
} catch (err) {
expect(err.response.status).toBe(404)
expect(err.response.data).toHaveProperty('message')
}
})
test('POST /users validates required fields', async () => {
try {
await client.post('/users', { email: 'invalid' }) // missing name
} catch (err) {
expect(err.response.status).toBe(422)
}
})
})Combining Prism with API Development Workflow
Frontend development without backend
- Write the OpenAPI spec together with the backend team
- Start
prism mock openapi.yaml - Frontend develops against the mock
- Backend implements the actual API
- Switch the frontend to point at the real backend — the contract was already agreed
Catching spec drift
As your API evolves, keep your spec updated. Run Prism in proxy mode against your real service in CI to catch spec drift:
# CI job
- name: Run proxy validation
run: |
prism proxy openapi.yaml https://staging-api.yourservice.com &
sleep 2
npm run test:integration -- --base-url http://localhost:4010If your API returns responses that don't match the spec, Prism logs warnings. Fail the CI job on validation errors with --errors flag:
prism proxy openapi.yaml https://api.example.com --errorsCustomizing Port and Host
# Different port
prism mock openapi.yaml --port 8080
<span class="hljs-comment"># Bind to all interfaces (for Docker)
prism mock openapi.yaml --host 0.0.0.0
<span class="hljs-comment"># Specific host
prism mock openapi.yaml --host localhost --port 4010Supported Spec Formats
- OpenAPI 3.0.x (YAML and JSON)
- OpenAPI 3.1.x
- Swagger 2.0 (YAML and JSON)
- Remote URLs:
prism mock https://api.example.com/openapi.yaml
Limitations
Prism is spec-driven — it can only respond based on what's in your OpenAPI document. It doesn't:
- Maintain state across requests
- Support conditional responses based on request state
- Handle complex business logic
For stateful mocking, combine Prism with Mockoon (for GUI-based development) or MSW (for browser tests). Use Prism where the priority is spec conformance and contract validation.
Conclusion
Prism turns your OpenAPI specification into a running mock server in seconds. More importantly, it closes the feedback loop between your spec and your implementation — request validation catches spec violations in client code, response validation catches them in server code.
For API-first teams, Prism is a natural fit. Write your spec, spin up Prism, and let frontend and backend teams work in parallel. When the real API is ready, your spec and your tests are already aligned.
Install with npm install -g @stoplight/prism-cli and start mocking with prism mock your-spec.yaml.