Mock Server
A powerful Node.js mock server that automatically generates realistic API responses from your OpenAPI/Swagger documents. It creates fully-functional endpoints with mock data, handles authentication, and respects content types - making it perfect for frontend development, API prototyping, and integration testing.
Features
- Perfect for frontend development and testing
- Creates endpoints automatically from OpenAPI documents
- Generates realistic mock data based on your schemas
- Handles authentication and responds with defined HTTP headers
- Supports Swagger 2.0 and OpenAPI 3.x documents
- Mocks event-driven APIs from AsyncAPI 3.1 documents over WebSocket and SSE
- Write custom JavaScript handlers for dynamic responses
- Automatically seed initial data on server startup
- Validates incoming requests against your OpenAPI contract
Quickstart
The easiest way to get started is through our Scalar CLI. You can have a mock server up and running in seconds:
npx @scalar/cli document mock openapi.json --watch
Docker
Alternatively, you can run the mock server in a Docker container. See the Docker documentation for more details.
Installation
For advanced use cases, you can integrate the mock server directly into your Node.js application for full control:
npm install @scalar/mock-server
Usage
import { serve } from '@hono/node-server'
import { createMockServer } from '@scalar/mock-server'
// Your OpenAPI document
const document = {
openapi: '3.1.1',
info: {
title: 'Hello World',
version: '1.0.0',
},
paths: {
'/foobar': {
get: {
responses: {
'200': {
description: 'OK',
content: {
'application/json': {
example: {
foo: 'bar',
},
},
},
},
},
},
},
},
}
// Create the mocked routes
const app = await createMockServer({
document,
// Custom logging
onRequest({ context, operation }) {
console.log(context.req.method, context.req.path)
},
})
// Start the server
serve(
{
fetch: app.fetch,
port: 3000,
},
(info) => {
console.log(`Listening on http://localhost:${info.port}`)
},
)
Authentication
You can define security schemes in your OpenAPI document and the mock server will validate the authentication:
import { serve } from '@hono/node-server'
import { createMockServer } from '@scalar/mock-server'
// Your OpenAPI document
const document = {
openapi: '3.1.1',
info: {
title: 'Hello World',
version: '1.0.0',
},
paths: {
'/secret': {
get: {
security: [
{
bearerAuth: [],
},
{
apiKey: [],
},
],
responses: {
'200': {
description: 'OK',
content: {
'application/json': {
example: {
foo: 'bar',
},
},
},
},
'401': {
description: 'Unauthorized',
content: {
'application/json': {
example: {
error: 'Unauthorized',
},
},
},
},
},
},
},
},
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
apiKey: {
type: 'apiKey',
in: 'header',
name: 'X-API-Key',
},
},
},
}
// Create the mocked routes
const app = await createMockServer({
document,
// Custom logging
onRequest({ context, operation }) {
console.log(context.req.method, context.req.path)
},
})
// Start the server
serve(
{
fetch: app.fetch,
port: 3000,
},
(info) => {
console.log(`Listening on http://localhost:${info.port}`)
},
)
OpenAPI endpoints
The given OpenAPI document is automatically exposed:
/openapi.jsonand/openapi.yaml
Selecting responses
By default the mock server picks a response (and its status code) for you and returns the first example it can find. You can override both with the standard Prefer header, just like Stoplight Prism.
Use code=<status> to request a specific response status:
# Returns the 404 response defined for the operation
curl http://localhost:3000/users/1 -H 'Prefer: code=404'
Use example=<name> to pick a named example from the examples map:
# Returns the `bob` example from the response
curl http://localhost:3000/users -H 'Prefer: example=bob'
Both directives are independent and can be combined. code= picks the response, then example= picks the example within it:
curl http://localhost:3000/users -H 'Prefer: code=422, example=missingEmail'
Unknown values fall back to the default behavior, so an undefined status code or example name never errors.
To define multiple examples, use the examples map on the response media type:
const document = {
openapi: '3.1.1',
info: {
title: 'Hello World',
version: '1.0.0',
},
paths: {
'/users': {
get: {
responses: {
'200': {
description: 'OK',
content: {
'application/json': {
examples: {
alice: {
value: { name: 'Alice' },
},
bob: {
value: { name: 'Bob' },
},
},
},
},
},
},
},
},
},
}
Advanced Features
Request Validation
The mock server enforces your OpenAPI contract by default. Each request is validated against the matched operation before a mock response is generated:
- Path, query, header, and cookie parameters declared in the operation are validated against their schema. Values arrive as strings, so
type: integer/booleanare coerced before validation (for example?limit=10becomes the number10). Required parameters are enforced. Header names are matched case-insensitively, and theAccept,Content-Type, andAuthorizationheaders are ignored as parameters because OpenAPI defines them elsewhere. - Array parameters are deserialized according to their
styleandexplodebefore validation. Explodedformarrays read repeated query keys (?ids=1&ids=2), whileform(non-exploded),spaceDelimited, andpipeDelimitedquery arrays,simplepath and header arrays,formcookie arrays, and thelabel(/.1.2.3) andmatrix(/;ids=1;ids=2) path styles are split on their delimiter. - Object parameters are deserialized too:
deepObject(?filter[min]=1&filter[max]=9), explodedform(properties as top-level keys,?r=100&g=200),form/simple/label/matrixin both explode modes (for exampler,100,g,200,r=100,g=200, or;point=x,1,y,2). - JSON request bodies are validated against
requestBody.content['application/json'].schema, andrequestBody.requiredis enforced.
When a request violates the contract, the server responds with 422 Unprocessable Entity and a application/problem+json body listing every violation, instead of a mock response.
To turn this off and always return a mock response regardless of the request, set validateRequest: false:
import { createMockServer } from '@scalar/mock-server'
const app = await createMockServer({
document,
// Opt out of request validation
validateRequest: false,
})
A failing request (for example a missing required limit query parameter and a wrong-typed body field) returns:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"error": "Request validation failed",
"violations": [
{ "location": "query", "path": "/limit", "message": "limit must be integer" },
{ "location": "body", "path": "/age", "message": "must be integer" }
]
}
Each violation reports its location (path, query, header, cookie, or body), a path pointing at the offending value, and a human-readable message. All violations are returned at once, not just the first.
This validates path, query, header, and cookie parameters (across every OpenAPI serialization style, including array and object values), plus JSON request bodies. Response validation, non-JSON bodies, and proxy mode are planned follow-ups.
Custom Request Handlers
Use the x-handler extension to write custom JavaScript code for handling requests. This gives you access to a store helper for data persistence, faker for generating realistic data, and full access to request/response objects.
Learn more about custom request handlers →
Data Seeding
Use the x-seed extension on your schemas to automatically populate initial data when the server starts. Perfect for having realistic test data available immediately.
Learn more about data seeding →
AsyncAPI Mocking
Point the mock server at an AsyncAPI 3.1 document to mock event-driven APIs. Channels are served over WebSocket and Server-Sent Events, and messages are generated from each message's payload schema. Additional protocols can be plugged in through the transports extension point.