multiAI Summary Pending

mock-server

Create and manage mock API servers for development and testing.

231 stars

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/mock-server/SKILL.md --create-dirs "https://raw.githubusercontent.com/aiskillstore/marketplace/main/skills/curiouslearner/mock-server/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/mock-server/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How mock-server Compares

Feature / Agentmock-serverStandard Approach
Platform SupportmultiLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Create and manage mock API servers for development and testing.

Which AI agents support this skill?

This skill is compatible with multi.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Mock Server Skill

Create and manage mock API servers for development and testing.

## Instructions

You are a mock API server expert. When invoked:

1. **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

2. **Configure Behavior**:
   - Set response delays/latency
   - Simulate error conditions
   - Return different responses based on input
   - Implement state management
   - Mock authentication

3. **Advanced Scenarios**:
   - Simulate network failures
   - Random error injection
   - Rate limiting simulation
   - Conditional responses
   - CORS configuration

4. **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
```bash
# Install
npm install -g json-server

# Create db.json
cat > db.json << EOF
{
  "users": [
    { "id": 1, "name": "John Doe", "email": "john@example.com" },
    { "id": 2, "name": "Jane Smith", "email": "jane@example.com" }
  ],
  "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)
```bash
# 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": "bob@example.com"}'

# PUT update user
curl -X PUT http://localhost:3000/users/1 \
  -H "Content-Type: application/json" \
  -d '{"id": 1, "name": "John Updated", "email": "john.new@example.com"}'

# 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
```javascript
// 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
```bash
npm install --save-dev msw
```

### REST API Mocking
```javascript
// 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: 'john@example.com' },
      { id: '2', name: 'Jane Smith', email: 'jane@example.com' }
    ]);
  }),

  // 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: 'john@example.com'
    });
  }),

  // 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 === 'user@example.com' && 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
```javascript
// 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)
```javascript
// 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
```bash
# 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
```yaml
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: "john@example.com"

  /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: "john@example.com"
        '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
```javascript
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: 'john@example.com' },
  { id: '2', name: 'Jane Smith', email: 'jane@example.com' }
];

// 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
```javascript
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: () => 'john@example.com',
    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
```javascript
const resolvers = {
  Query: {
    users: () => [
      { id: '1', name: 'John Doe', email: 'john@example.com' },
      { id: '2', name: 'Jane Smith', email: 'jane@example.com' }
    ],
    user: (_, { id }) => {
      const users = [
        { id: '1', name: 'John Doe', email: 'john@example.com' },
        { id: '2', name: 'Jane Smith', email: 'jane@example.com' }
      ];
      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
```bash
# 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": "john@example.com" }
    ]
  }
}
EOF
```

## Mock Data Generation

### Using Faker.js
```javascript
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
```javascript
// 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
```javascript
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
```javascript
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