Advanced Tutorial

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:

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 NameGenerated Value
email, user_emailalice@example.com
first_name, firstNameAlice
created_at, createdAt2026-05-15T10:30:00Z
phone, phone_number+1-555-123-4567
url, websitehttps://example.com/page
ip_address, ip192.168.1.1
uuid, id550e8400-e29b-41d4-a716-446655440000
price, amount29.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
Deterministic data for tests: Using --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:

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.