mock-server
About
This Claude Skill creates and manages mock API servers for development and testing scenarios. It can generate mock endpoints from OpenAPI specs, simulate various response behaviors like delays and errors, and handle both REST and GraphQL APIs. Developers should use it when they need to test against API dependencies without relying on actual backend services.
Documentation
Mock Server Skill
Create and manage mock API servers for development and testing.
Instructions
You are a mock API server expert. When invoked:
-
Create Mock Servers:
- Generate mock API endpoints from OpenAPI specs
- Create custom mock responses
- Simulate different response scenarios
- Mock REST and GraphQL APIs
- Handle various HTTP methods
-
Configure Behavior:
- Set response delays/latency
- Simulate error conditions
- Return different responses based on input
- Implement state management
- Mock authentication
-
Advanced Scenarios:
- Simulate network failures
- Random error injection
- Rate limiting simulation
- Conditional responses
- CORS configuration
-
Integration:
- Proxy to real APIs
- Record and replay requests
- Generate mock data
- Integration with testing frameworks
Usage Examples
@mock-server
@mock-server --from-openapi
@mock-server --port 3000
@mock-server --with-delays
@mock-server --graphql
JSON Server (Simple Mock)
Quick Setup
# Install
npm install -g json-server
# Create db.json
cat > db.json << EOF
{
"users": [
{ "id": 1, "name": "John Doe", "email": "[email protected]" },
{ "id": 2, "name": "Jane Smith", "email": "[email protected]" }
],
"posts": [
{ "id": 1, "title": "Hello World", "userId": 1 },
{ "id": 2, "title": "Mock APIs", "userId": 2 }
]
}
EOF
# Start server
json-server --watch db.json --port 3000
Available Endpoints (Auto-generated)
# GET all users
curl http://localhost:3000/users
# GET user by ID
curl http://localhost:3000/users/1
# POST new user
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name": "Bob", "email": "[email protected]"}'
# PUT update user
curl -X PUT http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"id": 1, "name": "John Updated", "email": "[email protected]"}'
# PATCH partial update
curl -X PATCH http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"name": "John Patched"}'
# DELETE user
curl -X DELETE http://localhost:3000/users/1
# Query parameters
curl "http://localhost:3000/users?_page=1&_limit=10"
curl "http://localhost:3000/users?_sort=name&_order=asc"
curl "http://localhost:3000/posts?userId=1"
Custom Routes
// routes.json
{
"/api/*": "/$1",
"/users/:id/posts": "/posts?userId=:id",
"/auth/login": "/login"
}
// Start with custom routes
json-server db.json --routes routes.json
Mock Service Worker (MSW)
Setup
npm install --save-dev msw
REST API Mocking
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw';
export const handlers = [
// GET users
http.get('/api/users', () => {
return HttpResponse.json([
{ id: '1', name: 'John Doe', email: '[email protected]' },
{ id: '2', name: 'Jane Smith', email: '[email protected]' }
]);
}),
// GET user by ID
http.get('/api/users/:userId', ({ params }) => {
const { userId } = params;
// Simulate not found
if (userId === '999') {
return new HttpResponse(null, { status: 404 });
}
return HttpResponse.json({
id: userId,
name: 'John Doe',
email: '[email protected]'
});
}),
// POST create user
http.post('/api/users', async ({ request }) => {
const data = await request.json();
// Simulate validation error
if (!data.email) {
return HttpResponse.json(
{ error: 'Email is required' },
{ status: 400 }
);
}
return HttpResponse.json(
{
id: '123',
...data,
createdAt: new Date().toISOString()
},
{ status: 201 }
);
}),
// PUT update user
http.put('/api/users/:userId', async ({ params, request }) => {
const { userId } = params;
const data = await request.json();
return HttpResponse.json({
id: userId,
...data,
updatedAt: new Date().toISOString()
});
}),
// DELETE user
http.delete('/api/users/:userId', ({ params }) => {
return new HttpResponse(null, { status: 204 });
}),
// Simulate delay
http.get('/api/slow-endpoint', async () => {
await delay(2000); // 2 second delay
return HttpResponse.json({ message: 'Slow response' });
}),
// Simulate random errors
http.get('/api/unreliable', () => {
if (Math.random() > 0.5) {
return new HttpResponse(null, { status: 500 });
}
return HttpResponse.json({ status: 'ok' });
}),
// Authentication
http.post('/api/auth/login', async ({ request }) => {
const { email, password } = await request.json();
if (email === '[email protected]' && password === 'password') {
return HttpResponse.json({
accessToken: 'mock-jwt-token',
refreshToken: 'mock-refresh-token',
expiresIn: 3600
});
}
return HttpResponse.json(
{ error: 'Invalid credentials' },
{ status: 401 }
);
})
];
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Browser Setup
// src/mocks/browser.js
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
// src/index.js
if (process.env.NODE_ENV === 'development') {
const { worker } = await import('./mocks/browser');
await worker.start();
}
Node.js Setup (Testing)
// src/mocks/server.js
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
// src/tests/setup.js
import { server } from '../mocks/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Prism (OpenAPI-based)
From OpenAPI Spec
# Install
npm install -g @stoplight/prism-cli
# Start mock server from OpenAPI spec
prism mock openapi.yaml
# Specify port
prism mock openapi.yaml --port 4010
# Enable validation
prism mock openapi.yaml --errors
# Dynamic responses based on examples
prism mock openapi.yaml --dynamic
Example OpenAPI for Prism
openapi: 3.0.0
info:
title: Mock API
version: 1.0.0
paths:
/api/users:
get:
responses:
'200':
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
examples:
success:
value:
- id: "1"
name: "John Doe"
email: "[email protected]"
/api/users/{userId}:
get:
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/User'
examples:
user:
value:
id: "1"
name: "John Doe"
email: "[email protected]"
'404':
description: Not found
content:
application/json:
examples:
notFound:
value:
error: "User not found"
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
Express Mock Server
Custom Implementation
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
// Middleware for random delays
app.use((req, res, next) => {
const delay = Math.random() * 1000; // 0-1 second
setTimeout(next, delay);
});
// Middleware for authentication
app.use('/api/*', (req, res, next) => {
const token = req.headers.authorization;
if (!token || !token.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
});
// In-memory database
let users = [
{ id: '1', name: 'John Doe', email: '[email protected]' },
{ id: '2', name: 'Jane Smith', email: '[email protected]' }
];
// GET all users
app.get('/api/users', (req, res) => {
const { page = 1, limit = 10 } = req.query;
const start = (page - 1) * limit;
const end = start + parseInt(limit);
const paginatedUsers = users.slice(start, end);
res.json({
data: paginatedUsers,
meta: {
page: parseInt(page),
limit: parseInt(limit),
total: users.length,
totalPages: Math.ceil(users.length / limit)
}
});
});
// GET user by ID
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === req.params.id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// POST create user
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
// Validation
if (!name || !email) {
return res.status(400).json({
error: 'Validation failed',
details: {
name: !name ? 'Name is required' : undefined,
email: !email ? 'Email is required' : undefined
}
});
}
// Check duplicate email
if (users.some(u => u.email === email)) {
return res.status(409).json({ error: 'Email already exists' });
}
const newUser = {
id: String(Date.now()),
name,
email,
createdAt: new Date().toISOString()
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT update user
app.put('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === req.params.id);
if (index === -1) {
return res.status(404).json({ error: 'User not found' });
}
users[index] = {
...users[index],
...req.body,
updatedAt: new Date().toISOString()
};
res.json(users[index]);
});
// PATCH partial update
app.patch('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === req.params.id);
if (index === -1) {
return res.status(404).json({ error: 'User not found' });
}
users[index] = {
...users[index],
...req.body,
updatedAt: new Date().toISOString()
};
res.json(users[index]);
});
// DELETE user
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === req.params.id);
if (index === -1) {
return res.status(404).json({ error: 'User not found' });
}
users.splice(index, 1);
res.status(204).send();
});
// Error simulation endpoint
app.get('/api/simulate-error', (req, res) => {
const errorType = req.query.type || 'random';
if (errorType === 'timeout') {
// Never respond (timeout)
return;
}
if (errorType === 'random' && Math.random() > 0.5) {
return res.status(500).json({ error: 'Internal server error' });
}
res.json({ status: 'ok' });
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Mock server running on http://localhost:${PORT}`);
});
GraphQL Mock Server
Using Apollo Server
const { ApolloServer, gql } = require('apollo-server');
const { MockList } = require('@graphql-tools/mock');
// Schema
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
}
type Mutation {
createUser(name: String!, email: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
}
`;
// Mocks
const mocks = {
User: () => ({
id: () => Math.random().toString(36).substring(7),
name: () => 'John Doe',
email: () => '[email protected]',
posts: () => new MockList([2, 6])
}),
Post: () => ({
id: () => Math.random().toString(36).substring(7),
title: () => 'Sample Post',
content: () => 'This is mock content'
}),
Query: () => ({
users: () => new MockList([10, 20]),
posts: () => new MockList([20, 40])
})
};
const server = new ApolloServer({
typeDefs,
mocks,
mockEntireSchema: false
});
server.listen().then(({ url }) => {
console.log(`GraphQL mock server ready at ${url}`);
});
Custom Resolvers
const resolvers = {
Query: {
users: () => [
{ id: '1', name: 'John Doe', email: '[email protected]' },
{ id: '2', name: 'Jane Smith', email: '[email protected]' }
],
user: (_, { id }) => {
const users = [
{ id: '1', name: 'John Doe', email: '[email protected]' },
{ id: '2', name: 'Jane Smith', email: '[email protected]' }
];
return users.find(u => u.id === id);
}
},
Mutation: {
createUser: (_, { name, email }) => ({
id: Math.random().toString(36).substring(7),
name,
email
})
}
};
const server = new ApolloServer({
typeDefs,
resolvers
});
WireMock (Java-based)
Docker Setup
# Run WireMock in Docker
docker run -d \
--name wiremock \
-p 8080:8080 \
-v $(pwd)/wiremock:/home/wiremock \
wiremock/wiremock:latest
# Create mapping
mkdir -p wiremock/mappings
cat > wiremock/mappings/users.json << EOF
{
"request": {
"method": "GET",
"url": "/api/users"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": [
{ "id": "1", "name": "John Doe", "email": "[email protected]" }
]
}
}
EOF
Mock Data Generation
Using Faker.js
const { faker } = require('@faker-js/faker');
// Generate mock user
function generateUser() {
return {
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
avatar: faker.image.avatar(),
address: {
street: faker.location.streetAddress(),
city: faker.location.city(),
country: faker.location.country()
},
createdAt: faker.date.past().toISOString()
};
}
// Generate multiple users
function generateUsers(count = 10) {
return Array.from({ length: count }, generateUser);
}
// Generate posts
function generatePost() {
return {
id: faker.string.uuid(),
title: faker.lorem.sentence(),
content: faker.lorem.paragraphs(3),
author: generateUser(),
createdAt: faker.date.past().toISOString()
};
}
Advanced Scenarios
Conditional Responses
// Return different responses based on headers
http.get('/api/users', ({ request }) => {
const acceptLanguage = request.headers.get('Accept-Language');
if (acceptLanguage?.includes('es')) {
return HttpResponse.json({
mensaje: 'Hola Mundo'
});
}
return HttpResponse.json({
message: 'Hello World'
});
});
// Based on query parameters
http.get('/api/users', ({ request }) => {
const url = new URL(request.url);
const format = url.searchParams.get('format');
if (format === 'xml') {
return new HttpResponse(
'<users><user>John</user></users>',
{ headers: { 'Content-Type': 'application/xml' } }
);
}
return HttpResponse.json([{ name: 'John' }]);
});
Stateful Mocking
let requestCount = 0;
http.get('/api/rate-limit', () => {
requestCount++;
if (requestCount > 10) {
return HttpResponse.json(
{ error: 'Rate limit exceeded' },
{ status: 429 }
);
}
return HttpResponse.json({ count: requestCount });
});
Network Error Simulation
http.get('/api/network-error', () => {
return HttpResponse.error();
});
// Timeout simulation
http.get('/api/timeout', async () => {
await delay(30000); // 30 second timeout
return HttpResponse.json({});
});
Best Practices
Mock Server Design
- Mirror production API structure
- Use realistic data
- Implement proper error responses
- Support pagination
- Include rate limiting simulation
Data Management
- Use data generators for realistic mock data
- Maintain consistent data across requests
- Reset state between test runs
- Support CRUD operations
- Implement proper relationships
Response Scenarios
- Success responses (200, 201, 204)
- Client errors (400, 401, 403, 404, 409)
- Server errors (500, 502, 503)
- Network errors
- Timeouts
Development Workflow
- Start mock server before frontend development
- Use environment variables for API URLs
- Switch between mock and real API easily
- Document available endpoints
- Keep mock data synchronized with API
Testing
- Use mocks for isolated unit tests
- Test error handling
- Verify request validation
- Test authentication flows
- Simulate edge cases
Tools Comparison
| Tool | Best For | Complexity | Features |
|---|---|---|---|
| JSON Server | Quick prototypes | Low | Auto-CRUD, simple setup |
| MSW | Browser/Node testing | Medium | Request interception, powerful |
| Prism | OpenAPI specs | Low | Spec-based, validation |
| WireMock | Enterprise, Java | High | Recording, matching |
| Custom Express | Full control | Medium | Complete customization |
Notes
- Use mock servers during frontend development
- Keep mock responses synchronized with API contracts
- Test both success and failure scenarios
- Implement realistic delays for better testing
- Use environment variables to switch between mock/real APIs
- Document mock endpoints and behaviors
- Reset mock state between tests
- Use data generators for realistic data
- Implement proper CORS for browser testing
- Version mock data alongside API versions
Quick Install
/plugin add https://github.com/CuriousLearner/devkit/tree/main/mock-serverCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
evaluating-llms-harness
TestingThis Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.
langchain
MetaLangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.
webapp-testing
TestingThis Claude Skill provides a Playwright-based toolkit for testing local web applications through Python scripts. It enables frontend verification, UI debugging, screenshot capture, and log viewing while managing server lifecycles. Use it for browser automation tasks but run scripts directly rather than reading their source code to avoid context pollution.
finishing-a-development-branch
TestingThis skill helps developers complete finished work by verifying tests pass and then presenting structured integration options. It guides the workflow for merging, creating PRs, or cleaning up branches after implementation is done. Use it when your code is ready and tested to systematically finalize the development process.
