Prism: Spin Up a Mock Server from Your OpenAPI Spec

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-cli

Or run without installing:

npx @stoplight/prism-cli mock openapi.yaml

Docker:

docker run --rm -it stoplight/prism mock -h 0.0.0.0 openapi.yaml

Basic Usage

Given an OpenAPI spec, start a mock server:

prism mock openapi.yaml

Prism 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:

  1. Static examples defined in the spec (highest priority)
  2. Schema-based dynamic generation using the response schema and JSON Schema Faker
  3. 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_FOUND

Prism 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-time

Prism 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.com

Now 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 array

This 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-request

In 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 occurred

Selecting 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:api

Testing 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

  1. Write the OpenAPI spec together with the backend team
  2. Start prism mock openapi.yaml
  3. Frontend develops against the mock
  4. Backend implements the actual API
  5. 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:4010

If 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 --errors

Customizing 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 4010

Supported 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.

Read more