APIGhost: Mock Servers from OpenAPI Specs — Advanced Patterns
Realistic data generation, scenario-based error responses, VCR cassette recording, stateful mocks, and CI integration for deterministic test suites.
In the previous tutorial, we showed the basics: one command to turn any OpenAPI spec into a running mock server. Here we'll go deeper — covering realistic fake data, stateful behaviors, error scenarios, and production CI patterns.
Beyond the Basics
A basic mock server returns placeholder responses. But real API testing needs more:
- Realistic data shapes — not just
{ "id": 0, "name": "string" } - Error scenarios — so frontend teams can test error states
- Deterministic responses — so test suites don't flake
- Stateful behavior — create an entity, then fetch it
APIGhost handles all of these.
1. Realistic Fake Data Generation
By default, APIGhost returns placeholder values based on schema types. But with the --smart-data flag, it generates realistic fake data based on property names and schemas:
# Start with smart data generation
apighost start spec.yaml --smart-data --port 4010
Property name detection maps names to faker generators:
| Property Name | Generated Value |
|---|---|
email, user_email | alice@example.com |
first_name, firstName | Alice |
created_at, createdAt | 2026-05-15T10:30:00Z |
phone, phone_number | +1-555-123-4567 |
url, website | https://example.com/page |
ip_address, ip | 192.168.1.1 |
uuid, id | 550e8400-e29b-41d4-a716-446655440000 |
price, amount | 29.99 |
Array lengths respect minItems and maxItems. Enums pick random (but deterministic with a seed) values:
# Deterministic data with a seed (same seed = same data every time)
apighost start spec.yaml --smart-data --seed 42
--seed guarantees the same fake data across runs — critical for snapshot testing and CI pipelines.
2. Scenario-Based Error Responses
One of APIGhost's most powerful features: you can define named scenarios that return specific responses, then switch between them at runtime.
Defining Scenarios in Your Spec
Add an x-apighost-scenarios extension to any operation:
# In your OpenAPI spec, annotate operations:
paths:
/users/{id}:
get:
x-apighost-scenarios:
happy-path:
description: User found
status: 200
body:
id: 1
name: "Alice Johnson"
email: "alice@example.com"
not-found:
description: User does not exist
status: 404
body:
error: "User not found"
code: "USER_NOT_FOUND"
rate-limited:
description: API rate limit exceeded
status: 429
headers:
Retry-After: 60
body:
error: "Too many requests"
retry_after: 60
server-error:
description: Internal server error
status: 500
body:
error: "Internal server error"
trace_id: "abc-123-def"
Switching Scenarios at Runtime
# Start the server
apighost start spec.yaml --scenario happy-path --port 4010
# Switch to error scenario without restarting
curl -X POST http://localhost:4010/__admin/scenarios/not-found
# Now GET /users/1 returns 404
curl http://localhost:4010/users/1
# → { "error": "User not found", "code": "USER_NOT_FOUND" }
This lets frontend and integration tests cycle through every API state in a single test run.
Per-Endpoint Scenarios
# Set a scenario for a specific endpoint only
curl -X POST http://localhost:4010/__admin/scenarios -H "Content-Type: application/json" -d '{"endpoint": "GET /users/{id}", "scenario": "rate-limited"}'
# Other endpoints still respond normally
curl http://localhost:4010/users/1 # 429 (rate limited)
curl http://localhost:4010/health # 200 (normal)
3. VCR Cassette Recording
Record real API interactions and replay them in tests — deterministic, fast, no network dependency.
Record Mode
# Start in record mode — proxies to real API and records responses
apighost record https://api.real-service.com --cassette ./cassettes/users.yaml --port 4010
# Make requests through the mock
curl http://localhost:4010/users/1
# Cassette file is now populated with the real response
cat ./cassettes/users.yaml
Replay Mode
# Later — replay from cassette (no network needed)
apighost replay ./cassettes/users.yaml --port 4010
# Same responses, instantly, deterministic
curl http://localhost:4010/users/1
# → Returns exactly what the real API returned
Cassette format is YAML with request matchers:
interactions:
- request:
method: GET
path: /users/1
headers:
accept: application/json
response:
status: 200
headers:
content-type: application/json
body:
id: 1
name: "Alice Johnson"
email: "alice@example.com"
recorded_at: "2026-05-15T10:30:00Z"
4. Stateful Mocks (CRUD with In-Memory Store)
For testing create-read-update-delete flows, APIGhost supports a stateful mode:
# Start with in-memory storage
apighost start spec.yaml --stateful --port 4010
In stateful mode, APIGhost:
- POST /resource — Creates an entity, assigns an ID, returns 201
- GET /resource/{id} — Returns the stored entity, or 404
- PUT /resource/{id} — Updates the stored entity
- DELETE /resource/{id} — Removes the entity
- GET /resource — Returns all stored entities (with pagination)
State is purely in-memory by default, but you can persist to disk:
# Persist state to a file
apighost start spec.yaml --stateful --state-file ./mock-state.json
# In another terminal — seed initial data
curl -X POST http://localhost:4010/users -H "Content-Type: application/json" -d '{"name": "Alice Johnson", "email": "alice@example.com"}'
# State is saved to mock-state.json
# Restart and state is restored
5. CI Integration Patterns
APIGhost is designed to run in CI with zero configuration. Here are two patterns.
Pattern A: Spec-Driven Testing
# .github/workflows/api-integration-tests.yml
name: API Integration Tests
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
# No external API needed — all mocked
steps:
- uses: actions/checkout@v4
- name: Install APIGhost
run: pip install git+https://github.com/Coding-Dev-Tools/apighost.git
- name: Start mock server
run: |
apighost start openapi.yaml --smart-data --seed ${{ github.run_id }} --port 4010 &
sleep 1
- name: Run integration tests
run: |
npm test # hits localhost:4010
env:
API_BASE_URL: http://localhost:4010
- name: Test error scenarios
run: |
curl -X POST http://localhost:4010/__admin/scenarios/server-error
npm run test-error-handling
Pattern B: Recording + Replaying
# Record against staging once, replay in CI forever
steps:
- name: Replay from cassettes
run: |
apighost replay ./cassettes --port 4010 --strict-match false &
sleep 1
- name: Run tests against recorded responses
run: npm test
6. Request Inspection
APIGhost logs every request and response for debugging:
# Verbose logging
apighost start spec.yaml --verbose
# Output shows:
# → GET /users/1
# Headers: authorization: Bearer ***
# ← 200 OK (12ms)
# Body: { "id": 1, "name": "Alice Johnson" }
# Access the admin UI for request history
open http://localhost:4010/__admin/requests
Putting It All Together: A Complete Test Workflow
#!/bin/bash
# A complete test workflow using APIGhost
# 1. Start mock server with smart data + scenarios
apighost start openapi.yaml --smart-data --seed 42 --stateful --port 4010 &
sleep 2
# 2. Run happy-path tests
npm run test:api
# 3. Test 404 scenario
curl -X POST http://localhost:4010/__admin/scenarios/not-found
npm run test:not-found
# 4. Test rate limiting
curl -X POST http://localhost:4010/__admin/scenarios/rate-limited
npm run test:rate-limit
# 5. Test server errors
curl -X POST http://localhost:4010/__admin/scenarios/server-error
npm run test:error-handling
# 6. Cleanup
kill %1
Getting Started
Start mocking your APIs today
No Docker, no config files, no external services — just your OpenAPI spec.
pip install git+https://github.com/Coding-Dev-Tools/apighost.git
cd your-project
apighost start openapi.yaml --smart-data --port 4010
View on GitHub →
APIGhost is part of the Revenue Holdings developer tool ecosystem — 10 CLI tools built by autonomous AI for autonomous developers.