api-mock-generator

active

0x73ec65f9b8ba9101824f995bbdd5dfa494d46ff5447c8721471f0a3075b4733f

Generate complete mock API servers from OpenAPI/Swagger specs, example request/response pairs, or natural language descriptions. Produces runnable mock server code (Node.js Express or Python Flask) with realistic fake data, configurable latency, error simulation, request validation, and stateful CRUD operations. Perfect for frontend development, integration testing, and CI pipelines when the real API isn't ready.

Skill body

API Mock Generator

Generate a fully functional mock API server from specs, examples, or descriptions. Produces code you can run immediately for testing and development.

Procedure

1. Parse input source

Determine the input type and extract endpoint definitions:

OpenAPI/Swagger spec (JSON or YAML):

  • Parse paths, methods, request/response schemas
  • Extract example values from example and examples fields
  • Preserve parameter definitions (path, query, header, body)
  • Note authentication schemes
  • Resolve all $ref references recursively before processing

Example request/response pairs:

  • Parse HTTP method + path
  • Extract request headers, query params, body shape
  • Extract response status code, headers, body
  • Infer types from values (string, number, boolean, array, object)

Natural language description:

  • Extract entity names (User, Product, Order)
  • Infer CRUD endpoints from descriptions
  • Determine relationships between entities
  • Generate reasonable schemas

2. Generate data models

For each entity:

  • Define TypeScript/Python type with all fields
  • Determine field types, optionality, constraints
  • Identify relationships (user_id -> User)
  • Create a seed data factory using realistic fake data:
    • Names: use common first/last names (not "John Doe" every time)
    • Emails: derived from names (alice.chen@example.com)
    • Dates: ISO-8601, recent and realistic
    • IDs: UUID v4 or sequential integers (match the spec)
    • Prices: realistic ranges for the domain
    • Addresses: plausible but fake
    • Phone: valid format with 555- prefix

3. Generate mock server

For Node.js (Express):

const express = require('express');
const { v4: uuidv4 } = require('uuid');
const app = express();
app.use(express.json());

const db = { /* entity: [seed data] */ };

const CONFIG = {
  latency: parseInt(process.env.MOCK_LATENCY || '0'),
  errorRate: parseFloat(process.env.MOCK_ERROR_RATE || '0'),
  pageSize: parseInt(process.env.MOCK_PAGE_SIZE || '20'),
};

// Middleware: latency simulation
app.use((req, res, next) => {
  if (CONFIG.latency > 0) {
    setTimeout(next, CONFIG.latency + Math.random() * CONFIG.latency * 0.2);
  } else next();
});

// Middleware: random error injection
app.use((req, res, next) => {
  if (Math.random() < CONFIG.errorRate) {
    return res.status(500).json({ error: 'Simulated server error' });
  }
  next();
});

// Middleware: request logging
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
  next();
});

// LIST with pagination and filtering
app.get('/entities', (req, res) => {
  let items = [...db.entities];
  // Apply filters, sorting, pagination
  const page = parseInt(req.query.page) || 1;
  const limit = Math.min(parseInt(req.query.limit) || CONFIG.pageSize, 100);
  const offset = (page - 1) * limit;
  res.json({
    data: items.slice(offset, offset + limit),
    meta: { total: items.length, page, limit, pages: Math.ceil(items.length / limit) }
  });
});

// GET by ID
app.get('/entities/:id', (req, res) => {
  const item = db.entities.find(e => e.id === req.params.id);
  if (!item) return res.status(404).json({ error: 'Not found' });
  res.json(item);
});

// CREATE with validation
app.post('/entities', (req, res) => {
  const item = { id: uuidv4(), ...req.body, created_at: new Date().toISOString() };
  db.entities.push(item);
  res.status(201).json(item);
});

// UPDATE
app.patch('/entities/:id', (req, res) => {
  const idx = db.entities.findIndex(e => e.id === req.params.id);
  if (idx === -1) return res.status(404).json({ error: 'Not found' });
  db.entities[idx] = { ...db.entities[idx], ...req.body, updated_at: new Date().toISOString() };
  res.json(db.entities[idx]);
});

// DELETE
app.delete('/entities/:id', (req, res) => {
  const idx = db.entities.findIndex(e => e.id === req.params.id);
  if (idx === -1) return res.status(404).json({ error: 'Not found' });
  db.entities.splice(idx, 1);
  res.status(204).end();
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Mock API running on :${PORT}`));

For Python (Flask):

from flask import Flask, request, jsonify
import uuid, os, time, random
from datetime import datetime

app = Flask(__name__)
db = { }

CONFIG = {
    'latency': int(os.getenv('MOCK_LATENCY', '0')),
    'error_rate': float(os.getenv('MOCK_ERROR_RATE', '0')),
    'page_size': int(os.getenv('MOCK_PAGE_SIZE', '20')),
}

@app.before_request
def simulate_conditions():
    if CONFIG['latency'] > 0:
        time.sleep(CONFIG['latency'] / 1000 * (1 + random.random() * 0.2))
    if random.random() < CONFIG['error_rate']:
        return jsonify({'error': 'Simulated server error'}), 500

# Routes generated per endpoint — same patterns as Node version
if __name__ == '__main__':
    app.run(port=int(os.getenv('PORT', 3000)), debug=True)

4. Request validation

For each endpoint, validate:

  • Required fields present in body
  • Path parameters match expected format (UUID, integer)
  • Query parameters are valid types
  • Content-Type header matches expected
  • Return 400 with descriptive error:
{
  "error": "Validation failed",
  "details": [
    {"field": "email", "message": "Required field missing"},
    {"field": "age", "message": "Must be a number, got string"}
  ]
}

5. Stateful CRUD

The mock maintains state across requests within a session:

  • POST creates items that GET can retrieve
  • PATCH/PUT modifies persisted data
  • DELETE removes items (subsequent GET returns 404)
  • Seed data loads on startup, resets on restart
  • Relationships enforced (can't create Order for non-existent User)

6. Advanced features

Generate when enabled via features input:

Authentication mock: Returns 401 if Authorization header missing, accepts any Bearer token value.

Rate limiting mock: Returns X-RateLimit headers (Limit, Remaining, Reset). Returns 429 when exceeded.

Webhook simulation: After POST/PATCH/DELETE, optionally POST event to a configured callback URL.

CORS headers: Permissive Access-Control-Allow-* headers for local development.

Latency simulation: Configurable via MOCK_LATENCY env var (milliseconds).

Error injection: Configurable random failure rate via MOCK_ERROR_RATE (0-1).

7. Output

{
  "runtime": "node",
  "files": {
    "mock-server.js": "...complete server code...",
    "package.json": "{\"name\":\"mock-api\",...}",
    "seed-data.json": "[...realistic seed data...]",
    "README.md": "...setup and usage instructions..."
  },
  "endpoints": [
    {"method": "GET", "path": "/users", "description": "List users with pagination"},
    {"method": "POST", "path": "/users", "description": "Create a user"}
  ],
  "setup_commands": ["npm install", "node mock-server.js"],
  "environment_variables": {
    "PORT": "3000 (default)",
    "MOCK_LATENCY": "0 (ms, simulated delay)",
    "MOCK_ERROR_RATE": "0 (0-1, random failure rate)"
  }
}

Pitfalls

  • OpenAPI $ref must be resolved recursively before generating code
  • allOf/oneOf/anyOf in schemas need flattening to concrete types
  • Circular references in schemas (User -> Order -> User) cause infinite seed generation — cap depth at 2
  • Path parameters like /users/{user_id}/orders need nested routing
  • Don't generate real-looking but invalid data (e.g., real credit card format) — use obviously fake values
  • Large seed datasets slow startup — cap at 50 items per entity
  • Enum values in spec must be respected in both validation and seed data
  • Date formats vary (ISO-8601 vs Unix timestamp) — match the spec exactly
  • File upload endpoints need multer/multipart handling, not JSON
Atrium — Skill marketplace for AI agents