MockForge

Crates.io Documentation CI License

MockForge helps teams simulate realistic backend behavior so frontend, backend, and QA work can move in parallel without waiting on live services.

Start with local open-source workflows, then add richer scenarios, protocol coverage, and team-facing tooling as your test surface grows.

What MockForge Is Good At

  • Turning OpenAPI specs into usable mock services quickly
  • Unblocking frontend and integration work with realistic responses
  • Testing retries, fallbacks, and edge cases with scenario-aware behavior
  • Simulating more than plain REST when your stack includes gRPC, GraphQL, WebSockets, or SMTP
  • Giving teams an admin surface and repeatable workflows instead of ad hoc fixture sprawl

Start Here

Quick Start

Installation

cargo install mockforge-cli

Basic Usage

# Start a mock server with an OpenAPI spec
cargo run -p mockforge-cli -- serve --spec examples/openapi-demo.json --http-port 3000

# Add WebSocket support with replay file
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl cargo run -p mockforge-cli -- serve --ws-port 3001

# Full configuration with Admin UI
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
cargo run -p mockforge-cli -- serve --spec examples/openapi-demo.json --admin --admin-port 9080

# Use configuration file
cargo run -p mockforge-cli -- serve --config demo-config.yaml

Next Steps

Core Capabilities

  • OpenAPI-first HTTP mocking with custom responses and dynamic data
  • Scenario-aware simulation for stateful behavior, latency, and failure paths
  • Multi-protocol coverage across REST, gRPC, GraphQL, WebSockets, and additional protocols
  • Admin UI and CLI workflows for local development and team usage
  • Extensibility through plugins, templates, and deeper configuration

Documentation Map

Examples

Check out the examples/ directory for sample configurations and use cases.

Product Model

MockForge is organized around five product pillars: Reality, Contracts, DevX, Cloud, and AI. If you want the full internal model behind the docs structure, see The Five Pillars.

Community

License

Licensed under either of:

at your option.

Getting Started with MockForge

Welcome to MockForge! This guide will get you up and running in minutes. MockForge is a powerful, multi-protocol mocking framework that helps frontend and backend teams work in parallel by providing realistic API mocks.

Table of Contents

What is MockForge?

MockForge is a comprehensive mocking framework that supports multiple protocols:

  • HTTP/REST APIs - Mock REST endpoints from OpenAPI/Swagger specs
  • WebSocket - Simulate real-time connections with replay and interactive modes
  • gRPC - Mock gRPC services from .proto files
  • GraphQL - Generate mock resolvers from GraphQL schemas

Why MockForge?

  • 🚀 Fast Setup: Go from OpenAPI spec to running mock server in seconds
  • 🔄 Multi-Protocol: Mock HTTP, WebSocket, gRPC, and GraphQL in one tool
  • 🎯 Realistic Data: Generate intelligent mock data with faker functions and templates
  • 🔌 Extensible: Plugin system for custom authentication, templates, and data sources
  • 📊 Admin UI: Visual interface for monitoring and managing mock servers

The Five Pillars of MockForge

MockForge is built on five foundational pillars that guide every feature we build. Understanding these pillars helps you see how MockForge delivers value across different aspects of API mocking:

[Reality] – Everything that makes mocks feel like a real, evolving backend

Make mocks indistinguishable from production backends through realistic behavior, state management, and dynamic data generation. Features like Reality Continuum, Smart Personas, Chaos Lab, and Temporal Simulation ensure your mocks behave like real systems.

Key Features:

  • Reality Continuum and Reality Slider for configurable realism levels
  • Smart Personas for consistent cross-endpoint data generation
  • Generative Schema Mode for dynamic mock data without seed data
  • Chaos Lab for network condition simulation
  • Multi-protocol support (HTTP, gRPC, WebSocket, Kafka, MQTT, AMQP, SMTP, FTP, TCP)

[Contracts] – Schema, drift, validation, and safety nets

Ensure API contracts are correct, validated, and stay in sync with real backends. Features like AI Contract Diff, automatic API sync, and comprehensive validation help catch breaking changes before they reach production.

Key Features:

  • OpenAPI/GraphQL schema validation
  • AI Contract Diff for contract comparison and visualization
  • Automatic API Sync & Change Detection
  • Request/response validation with detailed error reporting
  • Contract drift detection and monitoring

[DevX] – SDKs, generators, playgrounds, ergonomics

Make MockForge effortless to use, integrate, and extend for developers. Native SDKs for 6 languages, client code generators, interactive playgrounds, and comprehensive tooling ensure a smooth developer experience.

Key Features:

  • Multi-language SDKs (Rust, Node.js, Python, Go, Java, .NET)
  • Client code generators (React, Vue, Angular, Svelte)
  • GraphQL + REST Playground
  • CLI tool and Admin UI
  • Plugin system for extensibility

[Cloud] – Registry, orgs, governance, monetization, marketplace

Enable team collaboration, sharing, and scaling from solo developers to enterprise organizations. Cloud workspaces, scenario marketplace, registry server, and organization management help teams work together effectively.

Key Features:

  • Cloud Workspaces for team collaboration
  • Scenario Marketplace for sharing mock scenarios
  • Registry Server for centralized distribution
  • Organization Management for enterprise teams
  • Security controls and governance

[AI] – LLM/voice flows, AI diff/assist, generative behaviors

Leverage artificial intelligence to automate mock generation, enhance data realism, and assist developers. AI-powered features like MockAI, voice interface, and intelligent contract analysis make mock creation effortless.

Key Features:

  • MockAI for intelligent mock generation from natural language
  • Voice + LLM Interface for voice-driven mock creation
  • AI Contract Diff for intelligent contract analysis
  • AI Event Streams for narrative-driven WebSocket events
  • Generative data behaviors with RAG-powered synthesis

Learn More: See the complete Pillars documentation for detailed information about each pillar, feature mappings, and examples.

Choose Your Path

Depending on your role, team, or use case, you may want to start with a specific pillar:

  • Reality-First Onboarding - Start here if you care about realism. Perfect for frontend teams needing realistic data that evolves over time.
  • Contracts-First Onboarding - Start here if you’re a Platform/API team. Perfect for teams needing contract validation and drift detection.
  • AI-First Onboarding - Start here if you want natural-language-driven mocks. Perfect for rapid prototyping and AI-powered mock generation.

See Journeys by Pillar for a complete overview of all pillar-first onboarding journeys.

Installation

Prerequisites

MockForge requires one of:

  • Rust toolchain (for cargo install)
  • Docker (for containerized deployment)
cargo install mockforge-cli

Verify installation:

mockforge --version

Method 2: Docker

# Build the Docker image
git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
docker build -t mockforge .

# Run with default ports
docker run -p 3000:3000 -p 3001:3001 -p 9080:9080 mockforge

Method 3: Build from Source

git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
cargo build --release

# Install globally
cargo install --path crates/mockforge-cli

See Installation Guide for detailed instructions and troubleshooting.

Quick Start: Your First Mock API

Let’s create a simple mock API in 3 steps:

Step 1: Create an OpenAPI Specification

Create a file my-api.yaml:

openapi: 3.0.3
info:
  title: My First API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
    post:
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
  /users/{id}:
    get:
      summary: Get user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      required:
        - id
        - name
        - email
      properties:
        id:
          type: string
          example: "{{uuid}}"
        name:
          type: string
          example: "John Doe"
        email:
          type: string
          format: email
          example: "[email protected]"
        createdAt:
          type: string
          format: date-time
          example: "{{now}}"

Step 2: Start MockForge with Your Spec

mockforge serve --spec my-api.yaml --http-port 3000

You should see:

🚀 MockForge v1.0.0 starting...
📡 HTTP server listening on 0.0.0.0:3000
📋 OpenAPI spec loaded from my-api.yaml
✅ Ready to serve requests at http://localhost:3000

Step 3: Test Your Mock API

Open a new terminal and test your endpoints:

# List users
curl http://localhost:3000/users

# Get a specific user
curl http://localhost:3000/users/123

# Create a user
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Jane Smith", "email": "[email protected]"}'

Congratulations! You have a working mock API! 🎉

Enable Dynamic Data (Optional)

To get unique data on each request, enable template expansion:

# Stop the server (Ctrl+C), then restart with templates enabled
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  mockforge serve --spec my-api.yaml --http-port 3000

Now {{uuid}} and {{now}} in your spec will generate unique values!

Basic Configuration

Using a Configuration File

Create mockforge.yaml for better control:

http:
  port: 3000
  openapi_spec: my-api.yaml
  response_template_expand: true
  cors:
    enabled: true
    allowed_origins: ["http://localhost:3000"]

admin:
  enabled: true
  port: 9080

logging:
  level: info

Start with the config file:

mockforge serve --config mockforge.yaml

Environment Variables

All settings can be set via environment variables:

export MOCKFORGE_HTTP_PORT=3000
export MOCKFORGE_ADMIN_ENABLED=true
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true
export MOCKFORGE_LOG_LEVEL=debug

mockforge serve --spec my-api.yaml

See Configuration Reference for all options.

Common Use Cases

Frontend Development

Start a mock server and point your frontend to it:

# Terminal 1: Start mock server
mockforge serve --spec api.json --http-port 3000 --admin

# Terminal 2: Point frontend to mock server
export REACT_APP_API_URL=http://localhost:3000
npm start

API Contract Testing

Test that your API matches the OpenAPI specification:

# Request validation defaults to "enforce"; set it explicitly with an env var
MOCKFORGE_REQUEST_VALIDATION=enforce mockforge serve --spec api.json \
  --http-port 3000

Team Collaboration

Share mock configurations via Git:

# Commit your mock config
git add mockforge.yaml
git commit -m "Add user API mocks"

# Team members can use the same mocks
git pull
mockforge serve --config mockforge.yaml

Next Steps

Now that you have MockForge running, explore these resources:

Tutorials

User Guides

Reference

Examples

Troubleshooting

Server Won’t Start

# Check if port is in use
lsof -i :3000

# Use a different port
mockforge serve --spec my-api.yaml --http-port 3001

Templates Not Working

Enable template expansion:

MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec my-api.yaml

Need More Help?


Ready to dive deeper? Continue to the 5-Minute Tutorial or explore all available examples.

Installation

MockForge can be installed through multiple methods depending on your needs and environment. Choose the installation method that best fits your workflow.

Prerequisites

Before installing MockForge, ensure you have one of the following:

  • Rust toolchain (for cargo installation or building from source)
  • Docker (for containerized deployment)
  • Pre-built binaries (when available)

The easiest way to install MockForge is through Cargo, Rust’s package manager:

cargo install mockforge-cli

This installs the MockForge CLI globally on your system. After installation, you can verify it’s working:

mockforge --version

Updating

To update to the latest version:

cargo install mockforge-cli --force

Method 2: Docker (Containerized)

MockForge is also available as a Docker image, which is ideal for:

  • Isolated environments
  • CI/CD pipelines
  • Systems without Rust installed

Build Docker image

Since pre-built images are not yet published to Docker Hub, build the image locally:

# Clone and build
git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
docker build -t mockforge .

Run with basic configuration

docker run -p 3000:3000 -p 3001:3001 -p 50051:50051 -p 9080:9080 \
  -e MOCKFORGE_ADMIN_ENABLED=true \
  -e MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  mockforge

Alternative: Docker Compose

For a complete setup with all services:

git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
docker-compose up

Build from source (without Docker)

git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
docker build -t mockforge .

Method 3: Building from Source

For development or custom builds, you can build MockForge from source:

git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge
cargo build --release

The binary will be available at target/release/mockforge.

To install it system-wide after building:

cargo install --path crates/mockforge-cli

Verification

After installation, verify MockForge is working:

# Check version
mockforge --version

# View help
mockforge --help

# Start with example configuration
mockforge serve --spec examples/openapi-demo.json --http-port 3000

Platform Support

MockForge supports:

  • Linux (x86_64, aarch64)
  • macOS (x86_64, aarch64)
  • Windows (x86_64)
  • Docker (any platform with Docker support)

Windows install path

Every release ships a prebuilt mockforge-<version>-x86_64-pc-windows-msvc.zip asset on the GitHub releases page. Download it, unzip mockforge.exe into a directory on %PATH%, and mockforge --version works with no Rust toolchain or Visual Studio Build Tools installed. When release signing secrets are configured the binary is signed via Azure Trusted Signing, so SmartScreen does not warn on first run; unsigned builds may show the standard “unknown publisher” prompt.

If you prefer building from source:

  1. Install Rustup (the standard Rust installer for Windows). Pick the default x86_64-pc-windows-msvc toolchain when prompted; if you do not already have the Visual Studio Build Tools, Rustup will offer to download them.

  2. Open PowerShell (or cmd) and install:

    cargo install mockforge-cli --locked
    
  3. The binary lands at %USERPROFILE%\.cargo\bin\mockforge.exe, which cargo already added to %PATH%. Verify:

    mockforge --version
    

--locked pins the Cargo.lock shipped on crates.io, which avoids build breaks from later dependency drift.

If you would rather not compile locally, the Docker image runs on Windows under Docker Desktop / WSL2:

docker run --rm -p 3000:3000 -v ${PWD}:/work ghcr.io/saasy-solutions/mockforge:latest serve --spec /work/api.yaml --http-port 3000

We track first-class signed Windows binaries (no compile step, auto-update) at #884; contributions welcome.

Troubleshooting Installation

Cargo installation fails

If cargo install fails, ensure you have Rust installed:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Docker permission issues

If Docker commands fail with permission errors:

# Add user to docker group (Linux)
sudo usermod -aG docker $USER
# Log out and back in for changes to take effect

Port conflicts

If default ports (3000, 3001, 9080, 50051) are in use:

# Check what's using the ports
lsof -i :3000
lsof -i :3001

# Kill conflicting processes or use different ports
mockforge serve --http-port 3001 --ws-port 3002 --admin-port 8081

Next Steps

Once installed, proceed to the Quick Start guide to create your first mock server, or read about Basic Concepts to understand how MockForge works.

Your First Mock API in 5 Minutes

Scenario: Your frontend team needs a /users API to continue development, but the backend isn’t ready. Let’s create a working mock in 5 minutes.

Step 1: Install MockForge (30 seconds)

cargo install mockforge-cli

Or use the pre-built binary from the releases page.

Step 2: Create a Simple Config (1 minute)

You can either create a config manually or use the init command:

# Option A: Use the init command (recommended)
mockforge init .

# This creates mockforge.yaml with sensible defaults
# Then edit it to match the config below

# Option B: Create manually

Create a file called my-api.yaml (or edit the generated mockforge.yaml):

http:
  port: 3000
  routes:
    - path: /users
      method: GET
      response:
        status: 200
        body: |
          [
            {
              "id": "{{uuid}}",
              "name": "Alice Johnson",
              "email": "[email protected]",
              "createdAt": "{{now}}"
            },
            {
              "id": "{{uuid}}",
              "name": "Bob Smith",
              "email": "[email protected]",
              "createdAt": "{{now}}"
            }
          ]

    - path: /users/{id}
      method: GET
      response:
        status: 200
        body: |
          {
            "id": "{{request.path.id}}",
            "name": "Alice Johnson",
            "email": "[email protected]",
            "createdAt": "{{now}}"
          }

    - path: /users
      method: POST
      response:
        status: 201
        body: |
          {
            "id": "{{uuid}}",
            "name": "{{request.body.name}}",
            "email": "{{request.body.email}}",
            "createdAt": "{{now}}"
          }
mockforge config validate --config my-api.yaml

You should see:

✅ Configuration is valid

📊 Summary:
   Found 3 HTTP routes

Step 4: Start the Server (10 seconds)

mockforge serve --config my-api.yaml

You’ll see:

MockForge v1.0.0 starting...
HTTP server listening on 0.0.0.0:3000
Ready to serve requests at http://localhost:3000

Step 5: Test It (30 seconds)

Open a new terminal and test your endpoints:

# Get all users
curl http://localhost:3000/users

# Get a specific user
curl http://localhost:3000/users/123

# Create a new user
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Charlie Brown", "email": "[email protected]"}'

What just happened?

  • {{uuid}} generates a unique ID each time
  • {{now}} adds the current timestamp
  • {{request.path.id}} captures the ID from the URL
  • {{request.body.name}} reads data from POST requests

Step 6: Enable Dynamic Data (1 minute)

Want different data each time? Enable template expansion:

# Stop the server (Ctrl+C), then restart:
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --config my-api.yaml

Now every request returns unique UUIDs and timestamps!

Step 7: Add the Admin UI (30 seconds)

Want to see requests in real-time?

mockforge serve --config my-api.yaml --admin --admin-port 9080

Open http://localhost:9080 in your browser to see:

  • Live request logs
  • API metrics
  • Configuration controls

What’s Next?

In the next 5 minutes, you could:

  1. Use an OpenAPI Spec instead of YAML routes:

    mockforge serve --spec your-api.json --admin
    
  2. Add a Plugin for custom data generation:

    mockforge plugin install auth-jwt
    mockforge serve --config my-api.yaml --admin
    
  3. Mock a WebSocket for real-time features:

    websocket:
      port: 3001
      replay_file: chat-messages.jsonl
    
  4. Share with Your Team using workspace sync:

    mockforge sync --workspace-dir ./team-mocks
    git add team-mocks && git commit -m "Add user API mocks"
    

Common Next Steps

What You NeedWhere to Go
OpenAPI/Swagger integrationOpenAPI Guide
More realistic fake dataDynamic Data Guide
WebSocket/real-time mockingWebSocket Guide
gRPC service mockinggRPC Guide
Custom authenticationSecurity Guide
Team collaborationSync Guide

Troubleshooting

Port already in use?

mockforge serve --config my-api.yaml --http-port 8080

Templates not working? Make sure you set MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true or add it to your config:

http:
  response_template_expand: true

Config errors?

# Validate your configuration
mockforge config validate --config my-api.yaml

# See all available options
# https://github.com/SaaSy-Solutions/mockforge/blob/main/config.template.yaml

Need help?


Congratulations! You now have a working mock API that your frontend team can use immediately. The best part? As the real API evolves, just update your config file to match.

Quick Start

Get MockForge running in under 5 minutes with this hands-on guide. We’ll create a mock API server and test it with real HTTP requests.

Prerequisites

Ensure MockForge is installed and available in your PATH.

Step 1: Start a Basic HTTP Mock Server

MockForge can serve mock APIs defined in OpenAPI specifications. Let’s use the included example:

# Navigate to the MockForge directory (if building from source)
cd mockforge

# Start the server with the demo OpenAPI spec
mockforge serve --spec examples/openapi-demo.json --http-port 3000

You should see output like:

MockForge v0.1.0 starting...
HTTP server listening on 0.0.0.0:3000
OpenAPI spec loaded from examples/openapi-demo.json
Ready to serve requests at http://localhost:3000

Step 2: Test Your Mock API

Open a new terminal and test the API endpoints:

# Health check endpoint
curl http://localhost:3000/ping

Expected response:

{
  "status": "pong",
  "timestamp": "2025-09-12T17:20:01.512504405+00:00",
  "requestId": "550e8400-e29b-41d4-a716-446655440000"
}
# List users endpoint
curl http://localhost:3000/users

Expected response:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "name": "John Doe",
    "email": "[email protected]",
    "createdAt": "2025-09-12T17:20:01.512504405+00:00",
    "active": true
  }
]
# Create a new user
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Jane Smith", "email": "[email protected]"}'
# Get user by ID (path parameter)
curl http://localhost:3000/users/123

Step 3: Enable Template Expansion

MockForge supports dynamic content generation. Enable template expansion for more realistic data:

# Stop the current server (Ctrl+C), then restart with templates enabled
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
mockforge serve --spec examples/openapi-demo.json --http-port 3000

Now test the endpoints again - you’ll see different UUIDs and timestamps each time!

Step 4: Add WebSocket Support

MockForge can also mock WebSocket connections. Let’s add WebSocket support to our server:

# Stop the server, then restart with WebSocket support
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
mockforge serve --spec examples/openapi-demo.json --ws-port 3001 --http-port 3000

Step 5: Test WebSocket Connection

Test the WebSocket endpoint (requires Node.js or a WebSocket client):

# Using Node.js
node -e "
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:3001/ws');
ws.on('open', () => {
  console.log('Connected! Sending CLIENT_READY...');
  ws.send('CLIENT_READY');
});
ws.on('message', (data) => {
  console.log('Received:', data.toString());
  if (data.toString().includes('ACK')) {
    ws.send('ACK');
  }
  if (data.toString().includes('CONFIRMED')) {
    ws.send('CONFIRMED');
  }
});
ws.on('close', () => console.log('Connection closed'));
"

Expected WebSocket message flow:

  1. Send CLIENT_READY
  2. Receive welcome message with session ID
  3. Receive data message, respond with ACK
  4. Receive heartbeat messages
  5. Receive notification, respond with CONFIRMED

Step 6: Enable Admin UI (Optional)

For a visual interface to manage your mock server:

# Stop the server, then restart with admin UI
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
mockforge serve --spec examples/openapi-demo.json \
  --admin --admin-port 9080 \
  --http-port 3000 --ws-port 3001

Access the admin interface at: http://localhost:9080

Accessing the admin port from another machine

By default the admin port binds to 127.0.0.1 so it is only reachable from the same host. When mockforge runs in a VM or remote box and you want to point a mockforge-tui (or the admin UI in a browser) at it from another machine, use --admin-host 0.0.0.0 to bind on every interface:

mockforge serve --spec examples/openapi-demo.json \
  --admin --admin-port 9080 --admin-host 0.0.0.0 \
  --http-port 3000

Then on the other machine:

mockforge-tui --admin-url http://<vm-ip>:9080

Use --admin-host :: to dual-stack bind on IPv6 + IPv4-mapped-IPv6.

Security note: 0.0.0.0 exposes the admin API on every interface in your network. The admin API is auth-less by default; pair the bind with auth_required: true in your config when the host has any untrusted network. Inside an air-gapped lab / docker network this is fine.

Step 7: Using Configuration Files

Instead of environment variables, you can use a configuration file:

# Stop the server, then start with config file
mockforge serve --config demo-config.yaml

Step 8: Docker Alternative

If you prefer Docker:

# Build and run with Docker
docker build -t mockforge .
docker run -p 3000:3000 -p 3001:3001 -p 9080:9080 \
  -e MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  -e MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
  mockforge

What’s Next?

Congratulations! You now have a fully functional mock server running. Here are some next steps:

Troubleshooting

Server won’t start

  • Check if ports 3000, 3001, or 9080 are already in use
  • Verify the OpenAPI spec file path is correct
  • Ensure MockForge is properly installed

Template variables not working

  • Make sure MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true is set
  • Check that template syntax {{variable}} is used correctly

WebSocket connection fails

  • Verify WebSocket port (default 3001) is accessible
  • Check that MOCKFORGE_WS_REPLAY_FILE points to a valid replay file
  • Ensure the replay file uses the correct JSONL format

Need help?

Basic Concepts

Understanding MockForge’s core concepts will help you make the most of its capabilities. This guide explains the fundamental ideas behind MockForge’s design and functionality.

Multi-Protocol Architecture

MockForge is designed to mock multiple communication protocols within a single, unified framework:

HTTP/REST APIs

  • OpenAPI/Swagger Support: Define API contracts using industry-standard OpenAPI specifications
  • Dynamic Response Generation: Generate realistic responses based on request parameters
  • Request/Response Matching: Route requests to appropriate mock responses based on HTTP methods, paths, and parameters

WebSocket Connections

  • Replay Mode: Simulate scripted message sequences from recorded interactions
  • Interactive Mode: Respond dynamically to client messages
  • State Management: Maintain connection state across message exchanges

gRPC Services

  • Protocol Buffer Integration: Mock services defined with .proto files
  • Dynamic Service Discovery: Automatically discover and compile .proto files
  • Streaming Support: Handle unary, server streaming, client streaming, and bidirectional streaming
  • Reflection Support: Built-in gRPC reflection for service discovery

Response Generation Strategies

MockForge offers multiple approaches to generating mock responses:

1. Static Responses

Define fixed response payloads that are returned for matching requests:

{
  "status": "success",
  "data": {
    "id": 123,
    "name": "Example Item"
  }
}

2. Template-Based Dynamic Responses

Use template variables for dynamic content generation:

{
  "id": "{{uuid}}",
  "timestamp": "{{now}}",
  "randomValue": "{{randInt 1 100}}",
  "userData": "{{request.body}}"
}

3. Scenario-Based Responses

Define complex interaction scenarios with conditional logic and state management.

4. Advanced Data Synthesis (gRPC)

For gRPC services, MockForge provides sophisticated data synthesis capabilities:

  • Smart Field Inference: Automatically detects data types from field names (emails, phones, IDs)
  • Deterministic Generation: Reproducible test data with seeded randomness
  • Relationship Awareness: Maintains referential integrity across related entities
  • RAG-Driven Generation: Uses domain knowledge for contextually appropriate data

Template System

MockForge’s template system enables dynamic content generation using Handlebars-style syntax:

Built-in Template Functions

Data Generation

  • {{uuid}} - Generate unique UUID v4 identifiers
  • {{now}} - Current timestamp in ISO 8601 format
  • {{now+1h}} - Future timestamps with offset support
  • {{randInt min max}} - Random integers within a range
  • {{randFloat min max}} - Random floating-point numbers

Request Data Access

  • {{request.body}} - Access complete request body
  • {{request.body.field}} - Access specific JSON fields
  • {{request.path.param}} - Access URL path parameters
  • {{request.query.param}} - Access query string parameters
  • {{request.header.name}} - Access HTTP headers

Conditional Logic

  • {{#if condition}}content{{/if}} - Conditional content rendering
  • {{#each array}}item{{/each}} - Iterate over arrays

Template Expansion Control

Templates are only processed when explicitly enabled:

# Enable template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

This security feature prevents accidental template processing in production environments.

Configuration Hierarchy

MockForge supports multiple configuration methods with clear precedence:

1. Command Line Arguments (Highest Priority)

mockforge serve --http-port 3000 --ws-port 3001 --spec api.json

2. Environment Variables

MOCKFORGE_HTTP_PORT=3000
MOCKFORGE_WS_PORT=3001
MOCKFORGE_OPENAPI_SPEC_URL=file://./api.json

3. Configuration Files (Lowest Priority)

# config.yaml
server:
  http_port: 3000
  ws_port: 3001
spec: api.json

Server Modes

Development Mode

  • Template Expansion: Enabled by default for dynamic content
  • Verbose Logging: Detailed request/response logging
  • Admin UI: Enabled for visual server management
  • CORS: Permissive cross-origin requests

Production Mode

  • Template Expansion: Disabled by default for security
  • Minimal Logging: Essential information only
  • Performance Optimized: Reduced overhead for high-throughput scenarios

Request Matching

MockForge uses a sophisticated matching system to route requests to appropriate responses:

HTTP Request Matching

  1. Method Matching: GET, POST, PUT, DELETE, PATCH
  2. Path Matching: Exact path or parameterized routes
  3. Query Parameter Matching: Optional query string conditions
  4. Header Matching: Conditional responses based on request headers
  5. Body Matching: Match against request payload structure

Priority Order

  1. Most specific match first (method + path + query + headers + body)
  2. Fall back to less specific matches
  3. Default response for unmatched requests

State Management

For complex scenarios, MockForge supports maintaining state across requests:

Session State

  • Connection-specific data persists across WebSocket messages
  • HTTP session cookies maintain state between requests
  • Scenario progression tracks interaction flow

Global State

  • Shared data accessible across all connections
  • Configuration updates applied dynamically
  • Metrics and counters maintained server-wide

Extensibility

MockForge is designed for extension through multiple mechanisms:

Custom Response Generators

Implement custom logic for generating complex responses based on business rules.

Plugin System

Extend functionality through compiled plugins for specialized use cases.

Configuration Extensions

Add custom configuration options for domain-specific requirements.

Security Considerations

Template Injection Prevention

  • Templates are disabled by default in production
  • Explicit opt-in required for template processing
  • Input validation prevents malicious template injection

Access Control

  • Configurable CORS policies
  • Request rate limiting options
  • Authentication simulation support

Data Privacy

  • Request/response logging controls
  • Sensitive data masking capabilities
  • Compliance-friendly configuration options

Performance Characteristics

Throughput

  • HTTP APIs: 10,000+ requests/second (depending on response complexity)
  • WebSocket: 1,000+ concurrent connections
  • Memory Usage: Minimal overhead per connection

Scalability

  • Horizontal Scaling: Multiple instances behind load balancer
  • Resource Efficiency: Low CPU and memory footprint
  • Concurrent Users: Support for thousands of simultaneous connections

Integration Patterns

MockForge works well in various development and testing scenarios:

API Development

  • Contract-First Development: Mock APIs before implementation
  • Parallel Development: Frontend and backend teams work independently
  • Integration Testing: Validate API contracts between services

Microservices Testing

  • Service Virtualization: Mock dependent services during testing
  • Chaos Engineering: Simulate service failures and latency
  • Load Testing: Generate realistic traffic patterns

CI/CD Pipelines

  • Automated Testing: Mock external dependencies in test environments
  • Deployment Validation: Verify application behavior with mock services
  • Performance Benchmarking: Consistent test conditions across environments

This foundation will help you understand how to effectively use MockForge for your specific use case. The following guides provide detailed instructions for configuring and using each protocol and feature.

DevX-First Onboarding

Pillars: [DevX]

[DevX] - SDKs, generators, playgrounds, ergonomics

Start Here If…

You care about developer experience. You want easy-to-use SDKs, code generators, interactive playgrounds, and ergonomic tooling that makes working with mocks seamless.

Perfect for:

  • Developers who want to integrate mocks into their test suites quickly
  • Teams needing client code generation for their APIs
  • Developers who prefer interactive playgrounds over configuration files
  • Teams wanting plugin-based extensibility

Quick Start: 5 Minutes

Let’s get started with MockForge’s developer experience features:

# Install MockForge CLI
cargo install mockforge-cli

# Or use npm for Node.js SDK
npm install @mockforge-dev/sdk

# Or pip for Python SDK
pip install mockforge-sdk

Option 1: Use the SDK in Your Tests

Rust:

#![allow(unused)]
fn main() {
use mockforge_sdk::MockServer;

#[tokio::test]
async fn test_user_api() {
    let mut server = MockServer::new()
        .port(3000)
        .start()
        .await
        .expect("Failed to start server");

    server
        .stub_response("GET", "/api/users/{id}", json!({
            "id": "123",
            "name": "Test User",
            "email": "[email protected]"
        }))
        .await
        .expect("Failed to stub response");

    // Your test code here
    let client = reqwest::Client::new();
    let response = client
        .get("http://localhost:3000/api/users/123")
        .send()
        .await
        .unwrap();

    assert_eq!(response.status(), 200);
    
    server.stop().await.expect("Failed to stop server");
}
}

Node.js:

const { MockServer } = require('@mockforge-dev/sdk');

describe('User API', () => {
  let server;

  beforeAll(async () => {
    server = new MockServer({ port: 3000 });
    await server.start();
    
    await server.stubResponse('GET', '/api/users/{id}', {
      id: '123',
      name: 'Test User',
      email: '[email protected]'
    });
  });

  afterAll(async () => {
    await server.stop();
  });

  it('should return user data', async () => {
    const response = await fetch('http://localhost:3000/api/users/123');
    expect(response.status).toBe(200);
    const data = await response.json();
    expect(data.name).toBe('Test User');
  });
});

Python:

from mockforge_sdk import MockServer

def test_user_api():
    server = MockServer(port=3000)
    server.start()
    
    server.stub_response('GET', '/api/users/{id}', {
        'id': '123',
        'name': 'Test User',
        'email': '[email protected]'
    })
    
    # Your test code here
    import requests
    response = requests.get('http://localhost:3000/api/users/123')
    assert response.status_code == 200
    
    server.stop()

Option 2: Use the Interactive Playground

The playground is a page in the Admin UI. Start the server with the admin UI:

mockforge serve --spec openapi.yaml --admin

Then open http://localhost:9080 in your browser and select Playground to send REST and GraphQL requests to your mocks interactively.

Option 3: Generate Client Code

From an OpenAPI spec:

# Generate a React client (hooks + TypeScript types)
mockforge client generate --framework react --spec openapi.yaml --output ./src/api --include-types

# Other frameworks: vue, angular, svelte
mockforge client generate --framework vue --spec openapi.yaml --output ./src/api

# List supported frameworks
mockforge client list

Key DevX Features

1. Multi-Language SDKs

MockForge provides SDKs for:

  • Rust - Native SDK with full type safety
  • Node.js/TypeScript - NPM package with TypeScript definitions
  • Python - Pip package with async support
  • Go - Go module with idiomatic API
  • Java - Maven/Gradle package
  • .NET - NuGet package

2. Client Code Generation

Generate type-safe clients for:

  • TypeScript/JavaScript - Full type definitions
  • Python - With async/await support
  • React - Custom hooks for data fetching
  • Vue - Composition API composables
  • Angular - Injectable services
  • Svelte - Reactive stores

3. Interactive Playground

The playground (Admin UI) provides:

  • A list of the endpoints your mocks serve
  • REST and GraphQL request execution, with GraphQL introspection
  • Request history with replay
  • Code snippet generation for a request

4. CLI Tooling

Comprehensive CLI commands:

  • mockforge serve - Start mock server
  • mockforge generate - Generate mock servers from OpenAPI specs
  • mockforge config validate - Validate configurations
  • mockforge sync - Bidirectional workspace directory sync

5. Plugin System

Extend MockForge with plugins:

  • Custom authentication handlers
  • Data source plugins
  • Response generators
  • Template token resolvers

Next Steps

  1. Explore SDKs: Choose your language and integrate mocks into your tests
  2. Try the Playground: Use the Admin UI to send requests to your mocks interactively
  3. Generate Clients: Create type-safe API clients from your OpenAPI specs
  4. Build Plugins: Extend MockForge with custom functionality

Cross-Pillar Exploration

Once you’ve mastered DevX, explore these complementary pillars:

  • Add realism → Explore Reality features
  • Add validation → Explore Contracts features
  • Enable collaboration → Explore Cloud features
  • Enhance with AI → Explore AI features

Resources

Reality-First Onboarding

Pillars: [Reality]

[Reality] - Everything that makes mocks feel like a real, evolving backend

Start Here If…

You care about realism. You want mocks that feel indistinguishable from production backends, with realistic data, stateful behavior, and production-like network conditions.

Perfect for:

  • Frontend teams needing realistic data that evolves over time
  • Testing resilience and failure scenarios
  • Simulating production-like network conditions
  • Creating believable mock backends before real APIs exist

Quick Start: 5 Minutes

Let’s create a realistic mock API with Smart Personas and Reality Continuum:

# Install MockForge
cargo install mockforge-cli

# Create a simple config with reality features
cat > mockforge.yaml <<EOF
workspaces:
  - name: realistic-api
    reality:
      level: 3  # Moderate Realism
      personas:
        enabled: true
    endpoints:
      - path: /api/users/{id}
        method: GET
        response:
          body: |
            {
              "id": "{{persona.user.id}}",
              "name": "{{persona.user.name}}",
              "email": "{{persona.user.email}}"
            }
EOF

# Start the server
mockforge serve --config mockforge.yaml

Now test it:

# Request the same user ID multiple times - persona ensures consistency
curl http://localhost:3000/api/users/123
curl http://localhost:3000/api/users/123  # Same user data!

Key Reality Features

1. Reality Continuum

Blend mock and real data seamlessly:

reality:
  continuum:
    enabled: true
    blend_ratio: 0.5  # 50% mock, 50% real
    upstream_url: https://api.example.com

Why it matters: Develop against a backend that’s still under construction by gradually transitioning from mock to real.

Learn more: Reality Continuum Guide

2. Smart Personas

Generate consistent, relationship-aware data across endpoints:

reality:
  personas:
    enabled: true
    entities:
      - type: user
        fields:
          - name: id
            generator: uuid
          - name: email
            generator: email
      - type: order
        relationships:
          - field: user_id
            links_to: user.id

Why it matters: Maintain data consistency across your entire mock API. When you request a user and their orders, the relationships are preserved.

Learn more: Smart Personas Guide

3. Reality Slider

Adjust realism levels on the fly:

reality:
  level: 3  # 1=Static, 2=Light, 3=Moderate, 4=High, 5=Production Chaos

Why it matters: Instantly transform your mock environment to match different testing scenarios without manual configuration.

Learn more: Reality Slider Guide

4. Chaos Lab

Simulate network conditions and failures:

chaos:
  enabled: true
  latency:
    mean_ms: 200
    std_dev_ms: 50
  failures:
    error_rate: 0.05  # 5% of requests fail
    status_codes: [500, 502, 503]

Why it matters: Test how your application handles real-world network conditions and failures.

Learn more: Chaos Lab Guide

5. Temporal Simulation

Time travel and time-based data mutations:

time_travel:
  enabled: true
  virtual_clock: true
  scheduled_responses:
    - time: "2025-01-01T00:00:00Z"
      endpoint: /api/events
      response: {...}

Why it matters: Test time-dependent features, scheduled events, and data evolution over time.

Learn more: Time Travel Guide

Next Steps

Explore Reality Features

  1. Reality Continuum: Complete Guide

    • Learn about blend ratios and merge strategies
    • Configure time-based progression
    • Set up fallback handling
  2. Smart Personas: Complete Guide

    • Create persona graphs with relationships
    • Configure lifecycle states
    • Understand fidelity scores
  3. Reality Slider: Complete Guide

    • Understand reality levels
    • Configure hot-reload
    • Coordinate chaos, latency, and AI
  4. Chaos Lab: Complete Guide

    • Configure latency profiles
    • Set up failure injection
    • Simulate network conditions
  5. Temporal Simulation: Complete Guide

    • Use virtual clocks
    • Schedule time-based responses
    • Test time-dependent features

Once you’ve mastered Reality, explore these complementary pillars:

Examples

Example 1: Realistic E-Commerce API

workspaces:
  - name: ecommerce
    reality:
      level: 4  # High Realism
      personas:
        enabled: true
        entities:
          - type: user
          - type: product
          - type: order
            relationships:
              - field: user_id
                links_to: user.id
              - field: product_id
                links_to: product.id
    endpoints:
      - path: /api/users/{id}
        method: GET
        response:
          body: |
            {
              "id": "{{persona.user.id}}",
              "name": "{{persona.user.name}}",
              "orders": "{{persona.user.orders}}"
            }

Example 2: Production-Like Testing

reality:
  level: 5  # Production Chaos
chaos:
  enabled: true
  latency:
    distribution: normal
    mean_ms: 300
    std_dev_ms: 100
  failures:
    error_rate: 0.02
    status_codes: [500, 502, 503, 504]

Troubleshooting

Personas Not Working

Ensure personas are enabled in your config:

reality:
  personas:
    enabled: true

Reality Continuum Not Blending

Check your upstream URL and blend ratio:

reality:
  continuum:
    enabled: true
    blend_ratio: 0.5
    upstream_url: https://api.example.com  # Must be accessible

Chaos Not Injecting

Verify chaos is enabled and configured:

chaos:
  enabled: true
  latency:
    mean_ms: 200

Resources


Ready to dive deeper? Continue to the Reality Continuum Guide or explore all Reality features.

Contracts-First Onboarding

Pillars: [Contracts]

[Contracts] - Schema, drift, validation, and safety nets

Start Here If…

You’re a Platform/API team. You need to ensure API contracts are correct, validated, and stay in sync with real backends. You want to catch breaking changes before they reach production.

Perfect for:

  • API teams managing contract evolution
  • Platform teams ensuring contract consistency
  • Teams needing automatic API sync and change detection
  • Organizations requiring contract validation and drift monitoring

Quick Start: 5 Minutes

Let’s set up contract validation and drift detection:

# Install MockForge
cargo install mockforge-cli

# Create a config with contract validation
cat > mockforge.yaml <<EOF
workspaces:
  - name: api-contracts
    validation:
      mode: enforce  # disabled, warn, or enforce
      openapi_spec: https://api.example.com/openapi.json
    drift:
      enabled: true
      budgets:
        - endpoint: /api/users
          breaking_changes: 0
          non_breaking_changes: 5
    endpoints:
      - path: /api/users
        method: GET
        openapi_operation: getUsers
        response:
          body: |
            {
              "users": []
            }
EOF

# Start the server (request validation is "enforce" by default)
mockforge serve --config mockforge.yaml

Now test validation:

# Valid request - should succeed
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "[email protected]"}'

# Invalid request - should return 422 with validation errors
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"invalid": "field"}'

Key Contracts Features

1. Request/Response Validation

Validate requests and responses against OpenAPI schemas:

validation:
  mode: enforce  # disabled, warn, or enforce
  openapi_spec: ./api-spec.yaml
  strict_mode: true

Why it matters: Catch contract violations early, before they reach production. Get detailed 422 error responses that help developers fix issues quickly.

Learn more: Validation Guide

2. Contract Drift Detection

Monitor contract changes and detect breaking changes:

drift:
  enabled: true
  sync_interval: 3600  # Check every hour
  upstream_spec: https://api.example.com/openapi.json
  budgets:
    - endpoint: /api/users
      breaking_changes: 0  # No breaking changes allowed
      non_breaking_changes: 10  # Max 10 non-breaking changes

Why it matters: Stay informed about contract changes. Get alerts when drift budgets are exceeded. Prevent breaking changes from reaching consumers.

Learn more: Drift Budgets Guide

3. Automatic API Sync

Automatically sync contracts from upstream APIs:

sync:
  enabled: true
  sources:
    - url: https://api.example.com/openapi.json
      interval: 3600
      on_change: alert  # alert, update, or ignore

Why it matters: Keep mocks in sync with real APIs automatically. Get notified when upstream contracts change.

Learn more: API Sync Guide

4. AI Contract Diff

Intelligently compare and analyze contract changes:

ai_contract_diff:
  enabled: true
  llm_provider: openai
  analysis_depth: detailed

Why it matters: Understand the impact of contract changes. Get AI-powered recommendations for handling breaking changes.

Learn more: AI Contract Diff Guide

5. Multi-Protocol Contracts

Manage contracts across HTTP, gRPC, WebSocket, MQTT, and Kafka:

protocols:
  grpc:
    proto_files:
      - ./api.proto
    validation: true
  websocket:
    message_schemas:
      - type: user_message
        schema: ./schemas/user.json

Why it matters: Ensure contract consistency across all transport layers, not just HTTP/REST.

Learn more: Protocol Contracts Guide

Next Steps

Explore Contracts Features

  1. Validation: Complete Guide

    • Configure validation modes
    • Set up OpenAPI specs
    • Understand validation errors
  2. Drift Budgets: Complete Guide

    • Define drift budgets
    • Configure GitOps integration
    • Set up alerts
  3. API Sync: Complete Guide

    • Configure automatic sync
    • Set up change detection
    • Handle sync events
  4. Protocol Contracts: Complete Guide

    • Manage gRPC contracts
    • Configure WebSocket schemas
    • Set up MQTT/Kafka contracts
  5. AI Contract Diff: Complete Guide

    • Enable AI analysis
    • Understand recommendations
    • Handle breaking changes

Once you’ve mastered Contracts, explore these complementary pillars:

Examples

Example 1: Strict Validation

workspaces:
  - name: strict-api
    validation:
      mode: enforce
      openapi_spec: ./api-spec.yaml
      strict_mode: true
      validate_responses: true
    endpoints:
      - path: /api/users
        method: POST
        openapi_operation: createUser
        response:
          body: |
            {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "email": "{{faker.email}}"
            }

Example 2: Drift Monitoring

drift:
  enabled: true
  sync_interval: 1800  # Check every 30 minutes
  upstream_spec: https://api.example.com/openapi.json
  budgets:
    - endpoint: /api/users
      breaking_changes: 0
      non_breaking_changes: 5
      field_churn_percent: 10
    - endpoint: /api/orders
      breaking_changes: 0
      non_breaking_changes: 10
  gitops:
    enabled: true
    on_violation: create_pr
    branch_prefix: contract-update

Example 3: Multi-Protocol Contracts

protocols:
  grpc:
    proto_files:
      - ./api.proto
    validation: true
    drift:
      enabled: true
  websocket:
    message_schemas:
      - type: user_message
        schema: ./schemas/user.json
    validation: true

Troubleshooting

Validation Not Working

Ensure validation mode is set correctly:

validation:
  mode: enforce  # Must be 'enforce' or 'warn', not 'disabled'
  openapi_spec: ./api-spec.yaml  # Must be valid OpenAPI spec

Drift Detection Not Triggering

Check your sync configuration:

drift:
  enabled: true
  sync_interval: 3600  # Must be > 0
  upstream_spec: https://api.example.com/openapi.json  # Must be accessible

Contract Sync Failing

Verify your upstream URL and network access:

# Test upstream accessibility
curl https://api.example.com/openapi.json

Resources


Ready to dive deeper? Continue to the Drift Budgets Guide or explore all Contracts features.

Cloud-First Onboarding

Pillars: [Cloud]

[Cloud] - Registry, orgs, governance, monetization, marketplace

Start Here If…

You’re a team or organization that needs collaboration, sharing, and governance. You want to share mock scenarios across teams, manage workspaces, and leverage the marketplace for pre-built scenarios.

Perfect for:

  • Teams needing to share mock scenarios
  • Organizations requiring workspace management
  • Teams wanting to discover and use marketplace scenarios
  • Organizations needing governance and access controls

Quick Start: 5 Minutes

Use this path when you need a shared workspace, cloud sync, and basic team collaboration around mocks.

# Install MockForge CLI
cargo install mockforge-cli

# Login to MockForge Cloud
mockforge cloud login

# Confirm which account you are authenticated as
mockforge cloud whoami

Option 1: Create a Shared Workspace

# Create a cloud workspace
mockforge cloud workspace create my-workspace --name "Shared API Mocks"

# Inspect workspace details
mockforge cloud workspace info my-workspace

# Invite a teammate
mockforge cloud team invite [email protected] --workspace my-workspace --role editor

# Link a local directory to the cloud workspace
mockforge cloud workspace link . my-workspace

# Start sync
mockforge cloud sync start --workspace my-workspace --watch

Option 2: Manage Team Access and Activity

# List team members
mockforge cloud team members --workspace my-workspace

# Review recent activity
mockforge cloud activity --workspace my-workspace

Option 3: Check Sync Health

# Current sync status
mockforge cloud sync status --workspace my-workspace

# Pending changes
mockforge cloud sync pending --workspace my-workspace

# Sync history
mockforge cloud sync history --workspace my-workspace

Key Cloud Features

1. Organization Management

  • Shared workspaces - Keep team mocks under a common cloud workspace
  • Basic access control flows - Invite collaborators and manage roles
  • Activity visibility - Review workspace-level team activity

2. Cloud Workspaces

  • Synchronization - Sync local and cloud workspaces
  • Linking - Connect a local project directory to a cloud workspace
  • History - Inspect sync history and pending changes
  • Team collaboration - Invite team members to a shared workspace

3. Advanced Cloud Surfaces

  • Federation - Compose multi-workspace systems for larger environments
  • Analytics - Query usage and coverage signals across workspaces
  • Pipelines - Event-driven automation crate and integration surface
  • Marketplace and governance - Present in the broader platform, but verify current deployment and command surface before standardizing team workflows around them

Example: Team Workflow

# 1. Authenticate
mockforge cloud login

# 2. Create a shared cloud workspace
mockforge cloud workspace create api-mocks --name "API Mocks"

# 3. Link the local repo to that workspace
mockforge cloud workspace link . api-mocks

# 4. Invite teammates
mockforge cloud team invite [email protected] --workspace api-mocks --role editor

# 5. Start sync and keep changes flowing
mockforge cloud sync start --workspace api-mocks --watch

Next Steps

  1. Authenticate: Run mockforge cloud login and confirm with mockforge cloud whoami
  2. Create a shared workspace: Use mockforge cloud workspace create
  3. Connect local work: Use mockforge cloud workspace link and mockforge cloud sync start
  4. Invite collaborators: Use mockforge cloud team invite
  5. Explore deeper cloud features carefully: Federation, analytics, and pipelines exist in the docs and codebase, but should be validated against your deployed environment before they become standard operating workflow

Cross-Pillar Exploration

Once you’ve mastered Cloud, explore these complementary pillars:

  • Add realism → Explore Reality features
  • Add validation → Explore Contracts features
  • Improve workflow → Explore DevX features
  • Enhance with AI → Explore AI features

Resources

AI-First Onboarding

Pillars: [AI]

[AI] - LLM/voice flows, AI diff/assist, generative behaviors

Start Here If…

You want natural-language-driven mocks. You want to generate mocks from descriptions, use voice commands, and leverage AI to automate mock creation and enhance data realism.

Perfect for:

  • Teams wanting to generate mocks from natural language descriptions
  • Developers who prefer conversational interfaces
  • Teams needing AI-powered contract analysis
  • Organizations wanting to automate mock generation

Quick Start: 5 Minutes

Let’s create a mock API using natural language:

# Install MockForge
cargo install mockforge-cli

# Start MockForge with AI features enabled
mockforge serve --ai-enabled

# Use MockAI to generate a mock from natural language
curl -X POST http://localhost:3000/__mockforge/ai/generate \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a REST API for a todo app with endpoints to list, create, update, and delete todos. Todos have id, title, description, completed status, and created date."
  }'

Or use the voice interface:

# Start voice mode
mockforge voice

# Say: "Create a REST API for a todo app with CRUD operations"

Key AI Features

1. MockAI - Natural Language Mock Generation

Generate complete mock APIs from natural language descriptions:

# Generate a mock API
curl -X POST http://localhost:3000/__mockforge/ai/generate \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a user management API with endpoints for registration, login, and profile management"
  }'

Why it matters: Create mocks instantly without writing YAML or code. Describe what you need in plain English, and MockAI generates the complete API.

Learn more: MockAI Guide

2. Voice + LLM Interface

Build mocks using voice commands:

# Start voice mode
mockforge voice

# Example commands:
# "Create a REST API for an e-commerce store"
# "Add an endpoint to get product details by ID"
# "Generate realistic product data with names, prices, and descriptions"

Why it matters: Build mocks hands-free using natural language. Perfect for rapid prototyping and iterative development.

Learn more: Voice Interface Guide

3. AI Contract Diff

Intelligently analyze and compare contract changes:

ai_contract_diff:
  enabled: true
  llm_provider: openai
  analysis_depth: detailed
  generate_recommendations: true

Why it matters: Understand the impact of contract changes with AI-powered analysis. Get recommendations for handling breaking changes.

Learn more: AI Contract Diff Guide

4. Generative Schema Mode

Generate complete API ecosystems from JSON examples:

generative_schema:
  enabled: true
  examples:
    - path: ./examples/user.json
      entity_type: user
    - path: ./examples/order.json
      entity_type: order

Why it matters: Create entire API ecosystems from a few example JSON payloads. Automatically infer routes, relationships, and schemas.

Learn more: Generative Schema Guide

5. AI Event Streams

Generate narrative-driven WebSocket events:

websocket:
  ai_streams:
    enabled: true
    narrative: "A user browsing an e-commerce site, adding items to cart, and completing a purchase"
    event_types:
      - page_view
      - product_view
      - add_to_cart
      - checkout

Why it matters: Create realistic, narrative-driven event streams for testing real-time features.

Learn more: AI Event Streams Guide

Next Steps

Explore AI Features

  1. MockAI: Complete Guide

    • Generate mocks from natural language
    • Refine and iterate on generated mocks
    • Understand AI generation rules
  2. Voice Interface: Complete Guide

    • Set up voice commands
    • Use conversational mode
    • Generate OpenAPI specs from voice
  3. AI Contract Diff: Complete Guide

    • Enable AI analysis
    • Understand recommendations
    • Handle breaking changes
  4. Generative Schema: Complete Guide

    • Generate APIs from JSON examples
    • Configure entity relationships
    • Customize route generation
  5. AI Event Streams: Complete Guide

    • Create narrative-driven events
    • Configure event types
    • Test real-time features

Once you’ve mastered AI, explore these complementary pillars:

Examples

Example 1: Natural Language Mock Generation

# Generate a complete e-commerce API
curl -X POST http://localhost:3000/__mockforge/ai/generate \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a REST API for an e-commerce store with products, cart, and checkout endpoints. Products have id, name, price, description, and stock. Cart items link to products and have quantity."
  }'

Example 2: Voice-Driven Development

# Start voice mode
mockforge voice

# Interactive session:
# You: "Create a user authentication API"
# MockForge: "I've created a user authentication API with /register and /login endpoints. Would you like to add password reset?"
# You: "Yes, add password reset with email verification"
# MockForge: "Added /reset-password and /verify-email endpoints. The API is ready!"

Example 3: AI-Enhanced Personas

reality:
  personas:
    enabled: true
    ai_generation: true
    ai_config:
      provider: openai
      model: gpt-4
      generate_relationships: true
      generate_lifecycle_states: true

Example 4: Generative Schema from Examples

generative_schema:
  enabled: true
  examples:
    - path: ./examples/user.json
      entity_type: user
      routes:
        - GET /users
        - GET /users/{id}
        - POST /users
        - PUT /users/{id}
        - DELETE /users/{id}
    - path: ./examples/order.json
      entity_type: order
      relationships:
        - field: user_id
          links_to: user.id

Troubleshooting

AI Generation Not Working

Ensure AI features are enabled:

ai:
  enabled: true
  provider: openai  # or anthropic, etc.
  api_key: ${OPENAI_API_KEY}

Voice Interface Not Responding

Check your microphone permissions and voice configuration:

voice:
  enabled: true
  provider: openai
  speech_to_text: true

AI Contract Diff Not Analyzing

Verify your LLM provider configuration:

ai_contract_diff:
  enabled: true
  llm_provider: openai
  api_key: ${OPENAI_API_KEY}

Resources


Ready to dive deeper? Continue to the MockAI Guide or explore all AI features.

Tutorials

Welcome to the MockForge tutorials! These step-by-step guides walk you through common workflows and real-world scenarios.

Each tutorial is designed to be completed in 5-10 minutes and focuses on a specific goal.

Getting Started Tutorials

Your First Mock API in 5 Minutes

Time: 5 minutes | Level: Beginner

The fastest way to get started with MockForge. Create a simple REST API from scratch and test it.

You’ll learn:

  • Basic YAML configuration
  • Template variables
  • Starting the server
  • Testing endpoints

Perfect for: First-time users who want to see MockForge in action immediately.


Common Workflow Tutorials

Mock a REST API from an OpenAPI Spec

Time: 3 minutes | Level: Beginner

Automatically generate mock endpoints from your OpenAPI/Swagger specification.

You’ll learn:

  • Loading OpenAPI specs
  • Auto-generated responses
  • Request validation
  • Overriding specific endpoints

Perfect for: Teams with existing API documentation who want instant mocks.


Admin UI Walkthrough

Time: 5 minutes | Level: Beginner

Discover MockForge’s visual interface for managing your mock server without editing config files.

You’ll learn:

  • Dashboard navigation
  • Live request logs
  • Fixture management
  • Latency and fault simulation
  • Full-text search

Perfect for: Visual learners and teams who prefer UI over CLI.


Add a Custom Plugin

Time: 10 minutes | Level: Intermediate

Extend MockForge with plugins for custom authentication, data generation, or business logic.

You’ll learn:

  • Installing pre-built plugins
  • Using plugins in configs
  • Creating your own plugin
  • Plugin security and permissions

Perfect for: Developers who need custom functionality beyond built-in features.


Scenario-Based Tutorials

Coming Soon

We’re working on tutorials for these common scenarios:

  • Frontend Development Workflow: Set up mocks for a React/Vue/Angular app
  • Microservices Testing: Mock a multi-service architecture
  • Team Collaboration: Share mocks with Git and workspace sync
  • CI/CD Integration: Use MockForge in automated testing pipelines
  • Performance Testing: Simulate load and measure application behavior
  • WebSocket Real-Time Apps: Mock chat, notifications, and live updates
  • gRPC Service Development: Work with Protocol Buffers and streaming

Want to see a specific tutorial? Open an issue with your suggestion!


Tutorial Format

Each tutorial follows this structure:

  1. Goal: What you’ll accomplish
  2. Time: How long it takes
  3. Prerequisites: What you need before starting
  4. Step-by-step instructions: Clear, numbered steps
  5. Code examples: Ready-to-use configurations
  6. Troubleshooting: Common issues and solutions
  7. What’s next: Related guides and advanced topics

How to Use These Tutorials

For Beginners

Start with “Your First Mock API in 5 Minutes”, then move to “Mock a REST API from an OpenAPI Spec” if you have existing API documentation.

For Teams

Have team members complete “Admin UI Walkthrough” to get comfortable with the visual interface, then explore “Team Collaboration” (coming soon) for multi-user workflows.

For Developers

Jump straight to “Add a Custom Plugin” if you need advanced customization, or start with the basic tutorials to understand core concepts first.

Contributing Tutorials

Found a tutorial helpful? Have ideas for new ones? We welcome contributions!

See our Contributing Guide for details on how to submit tutorial ideas or write your own.


Quick Reference

TutorialTimeLevelTags
Your First Mock API5 minBeginnerGetting Started, HTTP, Basic
Mock OpenAPI Spec3 minBeginnerHTTP, OpenAPI, Validation
Admin UI Walkthrough5 minBeginnerAdmin UI, Monitoring, Visual
Add Custom Plugin10 minIntermediatePlugins, Extension, WASM

Ready to start? Pick a tutorial above and follow along. Each one is designed to give you hands-on experience with MockForge’s powerful features.

The Golden Path: Blueprint → Dev-Setup → Integration

This guide walks you through the Golden Path - the fastest way to get from zero to a fully integrated mock API in your frontend application. This path is designed to take less than 10 minutes and provide a magical first experience.

Overview

The Golden Path consists of three steps:

  1. Blueprint: Start with a pre-configured app archetype
  2. Dev-Setup: One-command frontend integration
  3. Integration: Use generated code in your app

Step 1: Choose and Create from a Blueprint

Blueprints are pre-configured application archetypes that include:

  • Personas: Realistic user profiles with consistent data
  • Reality defaults: Optimized realism levels for your use case
  • Sample flows: Common workflows (signup, checkout, etc.)
  • Scenarios: Happy paths, known failures, and slow paths
  • Contracts: JSON Schema validation for endpoints
  • Playground collections: Pre-configured test scenarios

Available Blueprints

List available blueprints:

mockforge blueprint list

You’ll see blueprints like:

  • b2c-saas: B2C SaaS with authentication, subscriptions, and billing
  • ecommerce: E-commerce with products, cart, and checkout
  • banking-lite: Banking app with accounts, transactions, and transfers

Create Your Project

Choose a blueprint and create your project:

# For a B2C SaaS app
mockforge init my-saas-app --blueprint b2c-saas

# For an e-commerce app
mockforge init my-store --blueprint ecommerce

# For a banking app
mockforge init my-bank --blueprint banking-lite

This command:

  • Creates a new project directory
  • Copies all blueprint files (config, personas, flows, scenarios, contracts)
  • Sets up the mockforge.yaml configuration
  • Creates a README with API documentation

Explore What You Got

cd my-saas-app
ls -la

You’ll see:

  • mockforge.yaml - Main configuration
  • personas/ - User personas with consistent data
  • scenarios/ - Multi-step API workflows
  • contracts/ - JSON Schema validation
  • README.md - API documentation

Start the Mock Server

mockforge serve

Your mock API is now running! Visit http://localhost:3000 to see it in action.

Try it out:

# Test the signup endpoint
curl -X POST http://localhost:3000/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "password123"}'

Step 2: One-Command Frontend Integration

Now that your mock API is running, integrate it into your frontend application with a single command.

Supported Frameworks

The dev-setup command supports:

  • React / Next.js
  • Vue / Nuxt
  • Angular
  • Svelte

Run Dev-Setup

Navigate to your frontend project and run:

# For React
mockforge dev-setup react

# For Vue
mockforge dev-setup vue

# For Angular
mockforge dev-setup angular

# For Svelte
mockforge dev-setup svelte

What Dev-Setup Does

The command automatically:

  1. Detects your project structure - Finds your frontend framework and configuration
  2. Detects existing MockForge workspace - If you’re in a blueprint project, it auto-detects the config
  3. Auto-detects OpenAPI spec - Finds openapi.yaml, openapi.json, or spec in mockforge.yaml
  4. Generates typed client - Creates a fully-typed API client from your OpenAPI spec
  5. Creates framework examples - Generates example hooks/composables/services
  6. Sets up environment variables - Creates .env.mockforge.example with configuration
  7. Installs dependencies - Adds required packages to your package.json

Example Output

🚀 Setting up MockForge for react...

  ✓ Detected project root: /path/to/my-frontend
  ✓ Detected existing MockForge workspace configuration
    Base URL: http://localhost:3000
    Reality level: moderate
  ✓ Found OpenAPI spec: openapi.yaml
  ✓ Generated typed client: src/mockforge/client.ts
  ✓ Created React Query hooks: src/mockforge/hooks.ts
  ✓ Created example component: src/components/MockForgeExample.tsx
  ✓ Created environment template: .env.mockforge.example

✅ Setup complete!

Next steps:
  1. Copy .env.mockforge.example to .env.local
  2. Check out src/components/MockForgeExample.tsx
  3. Start using the generated hooks in your components

Step 3: Integrate into Your App

Now use the generated code in your application.

React / Next.js Example

import { useGetUsers, useCreateUser } from '@/mockforge/hooks';

function UsersList() {
  const { data: users, isLoading, error } = useGetUsers();
  const createUser = useCreateUser();

  const handleCreate = async () => {
    await createUser.mutateAsync({
      email: '[email protected]',
      name: 'New User',
    });
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <button onClick={handleCreate}>Create User</button>
      <ul>
        {users?.map(user => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </div>
  );
}

Vue / Nuxt Example

<template>
  <div>
    <button @click="createUser">Create User</button>
    <ul v-if="users">
      <li v-for="user in users" :key="user.id">
        {{ user.name }} - {{ user.email }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { useGetUsers, useCreateUser } from '@/mockforge/composables';

const { data: users, isLoading, error } = useGetUsers();
const { mutate: createUser } = useCreateUser();

const handleCreate = () => {
  createUser({
    email: '[email protected]',
    name: 'New User',
  });
};
</script>

Angular Example

import { Component } from '@angular/core';
import { UserService } from '@/mockforge/services/user.service';

@Component({
  selector: 'app-users',
  template: `
    <button (click)="createUser()">Create User</button>
    <ul>
      <li *ngFor="let user of users$ | async">
        {{ user.name }} - {{ user.email }}
      </li>
    </ul>
  `,
})
export class UsersComponent {
  users$ = this.userService.getUsers();

  constructor(private userService: UserService) {}

  createUser() {
    this.userService.createUser({
      email: '[email protected]',
      name: 'New User',
    }).subscribe();
  }
}

Svelte Example

<script>
  import { getUsers, createUser } from '@/mockforge/stores';

  let users = $state([]);

  $effect(() => {
    getUsers().then(data => users = data);
  });

  async function handleCreate() {
    await createUser({
      email: '[email protected]',
      name: 'New User',
    });
    // Refresh users
    users = await getUsers();
  }
</script>

<button on:click={handleCreate}>Create User</button>
<ul>
  {#each users as user}
    <li>{user.name} - {user.email}</li>
  {/each}
</ul>

Complete Workflow Example

Let’s walk through a complete example from start to finish:

1. Create Project from Blueprint

mockforge init my-saas-app --blueprint b2c-saas
cd my-saas-app

2. Start Mock Server

mockforge serve

The server starts on http://localhost:3000 with:

  • Authentication endpoints (/api/auth/*)
  • User management (/api/users/*)
  • Subscription management (/api/subscriptions/*)
  • Billing endpoints (/api/billing/*)

3. Set Up Frontend

In a separate terminal, navigate to your React app:

cd ../my-react-app
mockforge dev-setup react

This generates:

  • src/mockforge/client.ts - Typed API client
  • src/mockforge/hooks.ts - React Query hooks
  • src/components/MockForgeExample.tsx - Example component

4. Configure Environment

cp .env.mockforge.example .env.local

Edit .env.local:

NEXT_PUBLIC_MOCKFORGE_URL=http://localhost:3000
MOCKFORGE_REALITY_LEVEL=moderate

5. Use in Your App

// app/users/page.tsx
import { useGetUsers } from '@/mockforge/hooks';

export default function UsersPage() {
  const { data: users, isLoading } = useGetUsers();

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users?.map(user => (
          <li key={user.id}>
            {user.name} ({user.email})
          </li>
        ))}
      </ul>
    </div>
  );
}

6. Test the Integration

# Start your frontend app
npm run dev

# Visit http://localhost:3001 (or your app's port)
# You should see users loaded from the mock API!

Advanced Features

Using Personas

Blueprints include personas for consistent data. Use them in your tests:

// In your test or component
import { usePersona } from '@/mockforge/hooks';

// Use a specific persona
const { data: user } = useGetUser({ persona: 'premium-user' });

Using Scenarios

Test different scenarios (happy path, failures, slow paths):

// Activate a scenario
await activateScenario('happy-path-signup');

// Make API calls - they'll follow the scenario
const response = await signup({ email: '[email protected]' });

Config Validation

The VS Code extension provides real-time validation:

  1. Open mockforge.yaml in VS Code
  2. See inline errors for invalid configuration
  3. Get autocomplete for all options

Playground Integration

Test endpoints interactively:

  1. Hover over an endpoint reference in your code
  2. Click “Open in Playground”
  3. Test the endpoint with different parameters

Troubleshooting

Dev-Setup Can’t Find OpenAPI Spec

If dev-setup can’t auto-detect your OpenAPI spec:

# Specify it explicitly
mockforge dev-setup react --spec ./openapi.yaml

Mock Server Not Running

Make sure the mock server is running:

# In your blueprint project
mockforge serve

Type Errors in Generated Client

Regenerate the client:

mockforge dev-setup react --force

Port Conflicts

If port 3000 is in use:

# Change the port in mockforge.yaml
base_url: http://localhost:3001

# Or use environment variable
MOCKFORGE_HTTP_PORT=3001 mockforge serve

Next Steps

Now that you’ve completed the Golden Path:

  1. Explore Personas: Use different personas for varied test data
  2. Customize Reality: Adjust the reality slider for different test scenarios
  3. Add Scenarios: Create custom scenarios for your workflows
  4. Extend Contracts: Add more JSON Schema contracts for validation
  5. Create Custom Blueprints: Build your own blueprints for your team

Mock a REST API from an OpenAPI Spec

Goal: You have an OpenAPI specification (Swagger file) and want to automatically generate mock endpoints for frontend development.

Time: 3 minutes

What You’ll Learn

  • Load an OpenAPI/Swagger spec into MockForge
  • Auto-generate mock responses from schema definitions
  • Enable dynamic data with template expansion
  • Test your mocked API

Prerequisites

  • MockForge installed (Installation Guide)
  • An OpenAPI 3.0 or Swagger 2.0 spec file (JSON or YAML)

Step 1: Prepare Your OpenAPI Spec

Use your existing spec, or create a simple one for testing:

petstore-api.json:

{
  "openapi": "3.0.0",
  "info": {
    "title": "Pet Store API",
    "version": "1.0.0"
  },
  "paths": {
    "/pets": {
      "get": {
        "summary": "List all pets",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Pet"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a pet",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pet"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pet created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pet"
                }
              }
            }
          }
        }
      }
    },
    "/pets/{petId}": {
      "get": {
        "summary": "Get a pet by ID",
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pet"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Pet": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": {
            "type": "string",
            "example": "{{uuid}}"
          },
          "name": {
            "type": "string",
            "example": "Fluffy"
          },
          "species": {
            "type": "string",
            "example": "cat"
          },
          "age": {
            "type": "integer",
            "example": 3
          }
        }
      }
    }
  }
}

Step 2: Start MockForge with Your Spec

mockforge serve --spec petstore-api.json --http-port 3000

What happened? MockForge:

  • Parsed your OpenAPI spec
  • Created mock endpoints for all defined paths
  • Generated example responses from schemas

Step 3: Test the Auto-Generated Endpoints

# List all pets
curl http://localhost:3000/pets

# Create a pet
curl -X POST http://localhost:3000/pets \
  -H "Content-Type: application/json" \
  -d '{"name": "Rex", "species": "dog", "age": 5}'

# Get a specific pet
curl http://localhost:3000/pets/123

Step 4: Enable Dynamic Template Expansion

To get unique IDs and dynamic data on each request:

# Stop the server (Ctrl+C), then restart with templates enabled:
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
mockforge serve --spec petstore-api.json --http-port 3000

Now test again - the {{uuid}} in your schema examples will generate unique IDs!

Step 5: Add Request Validation

MockForge can validate requests against your OpenAPI schema:

MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
MOCKFORGE_REQUEST_VALIDATION=enforce \
mockforge serve --spec petstore-api.json --http-port 3000

Try sending an invalid request:

# This will fail validation (missing required 'name' field)
curl -X POST http://localhost:3000/pets \
  -H "Content-Type: application/json" \
  -d '{"species": "dog"}'

Response:

{
  "error": "request validation failed",
  "details": [
    {
      "path": "body.name",
      "code": "required",
      "message": "Missing required field: name"
    }
  ]
}

Step 6: Use a Configuration File (Optional)

For more control, create a config file:

petstore-config.yaml:

server:
  http_port: 3000

spec: petstore-api.json

validation:
  mode: enforce

response:
  template_expand: true

admin:
  enabled: true
  port: 9080

Start with config:

mockforge serve --config petstore-config.yaml

Advanced: Override Specific Responses

You can override auto-generated responses for specific endpoints:

petstore-config.yaml:

http:
  port: 3000
  openapi_spec: petstore-api.json
  response_template_expand: true

  # Override the GET /pets endpoint
  routes:
    - path: /pets
      method: GET
      response:
        status: 200
        body: |
          [
            {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "species": "cat",
              "age": {{randInt 1 15}}
            },
            {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "species": "dog",
              "age": {{randInt 1 15}}
            }
          ]

Step 7: Configure Request Validation

MockForge supports comprehensive OpenAPI request validation. Update your config to enable validation:

validation:
  mode: enforce          # Reject invalid requests
  aggregate_errors: true # Combine multiple validation errors
  status_code: 422       # Use 422 for validation errors

# Optional: Skip validation for specific routes
validation:
  overrides:
    "GET /health": "off"  # Health checks don't need validation

Test validation by sending an invalid request:

# This will fail validation (missing required fields)
curl -X POST http://localhost:3000/pets \
  -H "Content-Type: application/json" \
  -d '{"species": "dog"}'

Response:

{
  "error": "request validation failed",
  "status": 422,
  "details": [
    {
      "path": "body.name",
      "code": "required",
      "message": "Missing required field: name"
    }
  ]
}

Validation Modes

  • off: Disable validation completely
  • warn: Log warnings but allow invalid requests
  • enforce: Reject invalid requests with error responses

Common Use Cases

Use CaseConfiguration
Frontend developmentEnable CORS, template expansion
API contract testingEnable request validation (enforce mode)
Demo environmentsUse faker functions for realistic data
Integration testsDisable template expansion for deterministic responses

Troubleshooting

Spec not loading?

  • Verify the file path is correct
  • Check that the spec is valid OpenAPI 3.0 or Swagger 2.0
  • Use a validator like Swagger Editor

Validation too strict?

# Use 'warn' mode instead of 'enforce'
MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec petstore-api.json

Need custom responses?

Complete Workflow Example

Here’s a complete workflow for generating mocks from an OpenAPI spec and using them in development:

1. Start with OpenAPI Spec

# Your API team provides this spec
cat petstore-api.json

2. Generate Mock Server

# Start MockForge with the spec
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  mockforge serve --spec petstore-api.json --http-port 3000 --admin

3. Test Generated Endpoints

# All endpoints from the spec are now available
curl http://localhost:3000/pets
curl http://localhost:3000/pets/123
curl -X POST http://localhost:3000/pets -d '{"name": "Fluffy", "species": "cat"}'

4. Monitor in Admin UI

Visit http://localhost:9080 to see:

  • All requests in real-time
  • Request/response bodies
  • Response times
  • Error rates

5. Use in Frontend Development

Point your frontend app to the mock server:

// In your React/Vue/Angular app
const API_URL = 'http://localhost:3000';

fetch(`${API_URL}/pets`)
  .then(res => res.json())
  .then(data => console.log('Pets:', data));

6. Iterate as API Evolves

When the API spec changes:

# 1. Update the OpenAPI spec file
vim petstore-api.json

# 2. Restart MockForge (it auto-reloads from spec)
# Or use watch mode if available

# 3. Regenerate client code (if using code generation)
mockforge client generate --spec petstore-api.json --framework react

Best Practices

Organization

  1. Keep specs in version control

    git add petstore-api.json
    git commit -m "Add Pet Store API spec v1.2"
    
  2. Use environment-specific configs

    # mockforge.dev.yaml
    http:
      port: 3000
      response_template_expand: true
      cors:
        enabled: true
    
  3. Document any custom overrides

    # Custom route overrides
    http:
      routes:
        - path: /pets/{petId}
          method: GET
          response:
            # Override default response
            status: 200
            body: |
              {
                "id": "{{request.path.petId}}",
                "name": "Custom Pet",
                "species": "custom"
              }
    

Testing

  1. Use deterministic data for tests

    # Disable template expansion for consistent test data
    response:
      template_expand: false
    
  2. Enable validation for contract testing

    MOCKFORGE_REQUEST_VALIDATION=enforce mockforge serve --spec api.json
    
  3. Record test scenarios

    • Use Admin UI to record request/response pairs
    • Export as fixtures for automated tests

What’s Next?


Pro Tip: Keep your OpenAPI spec in version control alongside your mock configuration. As the real API evolves, update the spec and your frontend automatically benefits from the changes.

React + MockForge Workflow

Goal: Build a React application that uses MockForge as a backend mock server for development and testing.

Time: 10-15 minutes

Overview

This tutorial shows you how to:

  1. Set up MockForge with an OpenAPI specification
  2. Generate TypeScript client code for React
  3. Build a React app that consumes the mock API
  4. Develop and test frontend features against mock data

Prerequisites

  • MockForge installed (Installation Guide)
  • Node.js 16+ and npm/pnpm installed
  • Basic React and TypeScript knowledge

Step 1: Prepare Your OpenAPI Specification

Create or use an existing OpenAPI spec. For this tutorial, we’ll use a User Management API:

user-management-api.json:

{
  "openapi": "3.0.3",
  "info": {
    "title": "User Management API",
    "version": "1.0.0"
  },
  "paths": {
    "/users": {
      "get": {
        "summary": "List all users",
        "responses": {
          "200": {
            "description": "List of users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/User"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a user",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}": {
      "get": {
        "summary": "Get user by ID",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "required": ["id", "name", "email"],
        "properties": {
          "id": {
            "type": "string",
            "example": "{{uuid}}"
          },
          "name": {
            "type": "string",
            "example": "John Doe"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "[email protected]"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "{{now}}"
          }
        }
      },
      "UserInput": {
        "type": "object",
        "required": ["name", "email"],
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      }
    }
  }
}

Step 2: Start MockForge Server

Start the mock server with your OpenAPI spec:

# Terminal 1: Start MockForge
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  mockforge serve --spec user-management-api.json --http-port 3000 --admin

You should see:

🚀 MockForge v1.0.0 starting...
📡 HTTP server listening on 0.0.0.0:3000
✅ Ready to serve requests at http://localhost:3000

Tip: Keep this terminal running. The --admin flag enables the admin UI at http://localhost:9080 for monitoring requests.

Step 3: Create React Application

Create a new React app (or use an existing one):

# Create React app with TypeScript
npx create-react-app my-app --template typescript
cd my-app

Step 4: Generate TypeScript Client (Optional)

MockForge can generate type-safe React hooks from your OpenAPI spec:

# Install MockForge CLI as dev dependency
npm install --save-dev mockforge-cli

# Add to package.json scripts

Update package.json:

{
  "scripts": {
    "generate-client": "mockforge client generate --spec ../user-management-api.json --framework react --output ./src/generated",
    "start": "react-scripts start",
    "build": "react-scripts build"
  }
}

Generate the client:

npm run generate-client

This creates:

  • src/generated/types.ts - TypeScript type definitions
  • src/generated/hooks.ts - React hooks for API calls

Step 5: Configure React App

Option A: Using Generated Hooks

If you generated the client, use the hooks:

src/App.tsx:

import React, { useState } from 'react';
import { useGetUsers, useCreateUser } from './generated/hooks';
import type { UserInput } from './generated/types';

function App() {
  const { data: users, loading, error, refetch } = useGetUsers();
  const { execute: createUser, loading: creating } = useCreateUser();
  
  const [formData, setFormData] = useState<UserInput>({
    name: '',
    email: ''
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      await createUser(formData);
      setFormData({ name: '', email: '' });
      refetch(); // Refresh user list
    } catch (error) {
      console.error('Failed to create user:', error);
    }
  };

  if (loading) return <div>Loading users...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div className="App">
      <h1>User Management</h1>
      
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Name"
          value={formData.name}
          onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        />
        <input
          type="email"
          placeholder="Email"
          value={formData.email}
          onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        />
        <button type="submit" disabled={creating}>
          {creating ? 'Creating...' : 'Create User'}
        </button>
      </form>

      <ul>
        {users?.map(user => (
          <li key={user.id}>
            <strong>{user.name}</strong> - {user.email}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Option B: Manual Fetch Implementation

If you prefer manual implementation:

src/App.tsx:

import React, { useState, useEffect } from 'react';

interface User {
  id: string;
  name: string;
  email: string;
  createdAt: string;
}

function App() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [formData, setFormData] = useState({ name: '', email: '' });

  useEffect(() => {
    fetch('http://localhost:3000/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      })
      .catch(err => {
        console.error('Error fetching users:', err);
        setLoading(false);
      });
  }, []);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      const res = await fetch('http://localhost:3000/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(formData)
      });
      const newUser = await res.json();
      setUsers([...users, newUser]);
      setFormData({ name: '', email: '' });
    } catch (error) {
      console.error('Failed to create user:', error);
    }
  };

  if (loading) return <div>Loading...</div>;

  return (
    <div className="App">
      <h1>User Management</h1>
      
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Name"
          value={formData.name}
          onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        />
        <input
          type="email"
          placeholder="Email"
          value={formData.email}
          onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        />
        <button type="submit">Create User</button>
      </form>

      <ul>
        {users.map(user => (
          <li key={user.id}>
            <strong>{user.name}</strong> - {user.email}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Step 6: Configure API Base URL

Set the API URL as an environment variable:

.env.development:

REACT_APP_API_URL=http://localhost:3000

.env.production:

REACT_APP_API_URL=https://api.yourdomain.com

Update your fetch calls to use the environment variable:

const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:3000';

fetch(`${API_URL}/users`)

Step 7: Start React App

# Terminal 2: Start React app
npm start

Your React app will be available at http://localhost:3001 (or 3000 if available).

Step 8: Test the Integration

  1. Create a user: Fill out the form and submit
  2. View users: See the list update with new users
  3. Monitor requests: Open http://localhost:9080 (Admin UI) to see all requests

Development Workflow

Typical Development Cycle

  1. Start MockForge with your API spec
  2. Develop React features against mock data
  3. View requests in Admin UI for debugging
  4. Update spec as API evolves
  5. Regenerate client when spec changes

Updating API Spec

When the OpenAPI spec changes:

# Regenerate TypeScript client
npm run generate-client

# Restart MockForge with updated spec
# (Ctrl+C in Terminal 1, then restart)
mockforge serve --spec user-management-api.json --http-port 3000 --admin

Testing

Run tests against the mock server:

# Start mock server in background
mockforge serve --spec user-management-api.json --http-port 3000 &
SERVER_PID=$!

# Run tests
npm test

# Stop mock server
kill $SERVER_PID

Common Issues

CORS Errors

If you see CORS errors, enable CORS in MockForge config:

# mockforge.yaml
http:
  port: 3000
  cors:
    enabled: true
    allowed_origins: ["http://localhost:3000", "http://localhost:3001"]

Template Variables Not Expanding

Make sure template expansion is enabled:

MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve ...

Client Generation Fails

  • Ensure MockForge CLI is in PATH
  • Check OpenAPI spec is valid JSON/YAML
  • Verify framework name is correct (react, not reactjs)

Advanced Usage

Custom Hooks

Wrap generated hooks with custom logic:

import { useGetUsers as useGetUsersBase } from './generated/hooks';

export function useGetUsers() {
  const result = useGetUsersBase();
  
  // Add custom logic
  useEffect(() => {
    if (result.data) {
      console.log('Users loaded:', result.data.length);
    }
  }, [result.data]);
  
  return result;
}

Error Handling

Implement global error handling:

import { useGetUsers, useCreateUser } from './generated/hooks';

function App() {
  const { data, error } = useGetUsers();
  
  if (error) {
    // Show user-friendly error message
    return <ErrorDisplay error={error} />;
  }
  
  // ... rest of component
}

Request Interceptors

Add authentication or custom headers:

// In generated/hooks.ts, modify the base configuration
const apiConfig = {
  baseUrl: 'http://localhost:3000',
  headers: {
    'Authorization': `Bearer ${getToken()}`,
  }
};

Next Steps


Need help? Check the FAQ or Troubleshooting Guide.

Vue + MockForge Workflow

Goal: Build a Vue 3 application that uses MockForge as a backend mock server for development and testing.

Time: 10-15 minutes

Overview

This tutorial shows you how to:

  1. Set up MockForge with an OpenAPI specification
  2. Generate TypeScript client code for Vue 3
  3. Build a Vue app that consumes the mock API using Pinia
  4. Develop and test frontend features against mock data

Prerequisites

  • MockForge installed (Installation Guide)
  • Node.js 16+ and npm/pnpm installed
  • Basic Vue 3 and TypeScript knowledge

Step 1: Prepare Your OpenAPI Specification

Create or use an existing OpenAPI spec. We’ll use the same User Management API from the React tutorial:

user-management-api.json:

{
  "openapi": "3.0.3",
  "info": {
    "title": "User Management API",
    "version": "1.0.0"
  },
  "paths": {
    "/users": {
      "get": {
        "summary": "List all users",
        "responses": {
          "200": {
            "description": "List of users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/User"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a user",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}": {
      "get": {
        "summary": "Get user by ID",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "User details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "required": ["id", "name", "email"],
        "properties": {
          "id": {
            "type": "string",
            "example": "{{uuid}}"
          },
          "name": {
            "type": "string",
            "example": "John Doe"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "[email protected]"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "{{now}}"
          }
        }
      },
      "UserInput": {
        "type": "object",
        "required": ["name", "email"],
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      }
    }
  }
}

Step 2: Start MockForge Server

Start the mock server with your OpenAPI spec:

# Terminal 1: Start MockForge
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
  mockforge serve --spec user-management-api.json --http-port 3000 --admin

You should see:

🚀 MockForge v1.0.0 starting...
📡 HTTP server listening on 0.0.0.0:3000
✅ Ready to serve requests at http://localhost:3000

Tip: Keep this terminal running. The --admin flag enables the admin UI at http://localhost:9080.

Step 3: Create Vue Application

Create a new Vue 3 app with TypeScript:

# Create Vue app with TypeScript
npm create vue@latest my-app
cd my-app

# Select TypeScript when prompted
# Install dependencies
npm install

Step 4: Install Pinia (State Management)

npm install pinia

Set up Pinia in src/main.ts:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')

Step 5: Generate TypeScript Client (Optional)

MockForge can generate type-safe Vue composables from your OpenAPI spec:

# Install MockForge CLI as dev dependency
npm install --save-dev mockforge-cli

# Add to package.json scripts

Update package.json:

{
  "scripts": {
    "generate-client": "mockforge client generate --spec ../user-management-api.json --framework vue --output ./src/generated",
    "dev": "vite",
    "build": "vue-tsc && vite build"
  }
}

Generate the client:

npm run generate-client

This creates:

  • src/generated/types.ts - TypeScript type definitions
  • src/generated/composables.ts - Vue composables for API calls
  • src/generated/store.ts - Pinia store for state management

Step 6: Configure Vue App

Option A: Using Generated Composables

If you generated the client, use the composables:

src/App.vue:

<template>
  <div class="app">
    <h1>User Management</h1>
    
    <form @submit.prevent="handleSubmit">
      <input
        v-model="formData.name"
        type="text"
        placeholder="Name"
        required
      />
      <input
        v-model="formData.email"
        type="email"
        placeholder="Email"
        required
      />
      <button type="submit" :disabled="creating">
        {{ creating ? 'Creating...' : 'Create User' }}
      </button>
    </form>

    <div v-if="loading">Loading users...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <ul v-else>
      <li v-for="user in users" :key="user.id">
        <strong>{{ user.name }}</strong> - {{ user.email }}
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { useGetUsers, useCreateUser } from './generated/composables';
import type { UserInput } from './generated/types';

const { data: users, loading, error, refetch } = useGetUsers();
const { execute: createUser, loading: creating } = useCreateUser();

const formData = ref<UserInput>({
  name: '',
  email: ''
});

const handleSubmit = async () => {
  try {
    await createUser(formData.value);
    formData.value = { name: '', email: '' };
    refetch(); // Refresh user list
  } catch (error) {
    console.error('Failed to create user:', error);
  }
};
</script>

<style scoped>
.app {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

form {
  margin-bottom: 20px;
}

input {
  margin-right: 10px;
  padding: 8px;
}

button {
  padding: 8px 16px;
  cursor: pointer;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  padding: 10px;
  margin: 5px 0;
  background: #f5f5f5;
  border-radius: 4px;
}
</style>

Option B: Manual Implementation with Pinia Store

Create a Pinia store for user management:

src/stores/userStore.ts:

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

interface User {
  id: string;
  name: string;
  email: string;
  createdAt: string;
}

interface UserInput {
  name: string;
  email: string;
}

const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';

export const useUserStore = defineStore('users', () => {
  const users = ref<User[]>([]);
  const loading = ref(false);
  const error = ref<Error | null>(null);

  const userCount = computed(() => users.value.length);

  async function fetchUsers() {
    loading.value = true;
    error.value = null;
    try {
      const response = await fetch(`${API_URL}/users`);
      if (!response.ok) throw new Error('Failed to fetch users');
      users.value = await response.json();
    } catch (e) {
      error.value = e as Error;
      console.error('Error fetching users:', e);
    } finally {
      loading.value = false;
    }
  }

  async function createUser(input: UserInput) {
    loading.value = true;
    error.value = null;
    try {
      const response = await fetch(`${API_URL}/users`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(input)
      });
      if (!response.ok) throw new Error('Failed to create user');
      const newUser = await response.json();
      users.value.push(newUser);
    } catch (e) {
      error.value = e as Error;
      console.error('Error creating user:', e);
      throw e;
    } finally {
      loading.value = false;
    }
  }

  return {
    users,
    loading,
    error,
    userCount,
    fetchUsers,
    createUser
  };
});

Use the store in your component:

src/App.vue:

<template>
  <div class="app">
    <h1>User Management</h1>
    
    <form @submit.prevent="handleSubmit">
      <input
        v-model="formData.name"
        type="text"
        placeholder="Name"
        required
      />
      <input
        v-model="formData.email"
        type="email"
        placeholder="Email"
        required
      />
      <button type="submit" :disabled="userStore.loading">
        {{ userStore.loading ? 'Creating...' : 'Create User' }}
      </button>
    </form>

    <div v-if="userStore.loading && userStore.users.length === 0">
      Loading users...
    </div>
    <div v-else-if="userStore.error">
      Error: {{ userStore.error.message }}
    </div>
    <ul v-else>
      <li v-for="user in userStore.users" :key="user.id">
        <strong>{{ user.name }}</strong> - {{ user.email }}
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useUserStore } from './stores/userStore';

const userStore = useUserStore();
const formData = ref({ name: '', email: '' });

onMounted(() => {
  userStore.fetchUsers();
});

const handleSubmit = async () => {
  try {
    await userStore.createUser(formData.value);
    formData.value = { name: '', email: '' };
  } catch (error) {
    // Error already handled in store
  }
};
</script>

Step 7: Configure API Base URL

Set the API URL as an environment variable:

.env.development:

VITE_API_URL=http://localhost:3000

.env.production:

VITE_API_URL=https://api.yourdomain.com

Step 8: Start Vue App

# Terminal 2: Start Vue app
npm run dev

Your Vue app will be available at http://localhost:5173 (or next available port).

Step 9: Test the Integration

  1. Create a user: Fill out the form and submit
  2. View users: See the list update with new users
  3. Monitor requests: Open http://localhost:9080 (Admin UI) to see all requests

Development Workflow

Typical Development Cycle

  1. Start MockForge with your API spec
  2. Develop Vue features against mock data
  3. View requests in Admin UI for debugging
  4. Update spec as API evolves
  5. Regenerate client when spec changes

Updating API Spec

When the OpenAPI spec changes:

# Regenerate TypeScript client
npm run generate-client

# Restart MockForge with updated spec
# (Ctrl+C in Terminal 1, then restart)
mockforge serve --spec user-management-api.json --http-port 3000 --admin

Testing with Vitest

Create tests against the mock server:

src/components/__tests__/UserForm.spec.ts:

import { describe, it, expect, beforeEach } from 'vitest';
import { mount } from '@vue/test-utils';
import { setActivePinia, createPinia } from 'pinia';
import UserForm from '../UserForm.vue';

describe('UserForm', () => {
  beforeEach(() => {
    setActivePinia(createPinia());
  });

  it('creates a user', async () => {
    const wrapper = mount(UserForm);
    // Your test logic here
  });
});

Common Issues

CORS Errors

Enable CORS in MockForge config:

# mockforge.yaml
http:
  port: 3000
  cors:
    enabled: true
    allowed_origins: ["http://localhost:5173", "http://localhost:3000"]

Template Variables Not Expanding

Make sure template expansion is enabled:

MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve ...

Environment Variables Not Loading

Vite requires the VITE_ prefix for environment variables. Ensure your .env file uses:

VITE_API_URL=http://localhost:3000

Advanced Usage

Reactive Data with Computed Properties

<script setup lang="ts">
import { computed } from 'vue';
import { useUserStore } from './stores/userStore';

const userStore = useUserStore();

const activeUsers = computed(() => 
  userStore.users.filter(u => !u.deleted)
);
</script>

Error Handling with Vue Toast

import { useToast } from 'vue-toastification';

const toast = useToast();

async function createUser(input: UserInput) {
  try {
    await userStore.createUser(input);
    toast.success('User created successfully!');
  } catch (error) {
    toast.error('Failed to create user');
  }
}

Next Steps


Need help? Check the FAQ or Troubleshooting Guide.

Admin UI Walkthrough

Goal: Use MockForge’s Admin UI to visually manage your mock server, view live logs, and configure settings without editing files.

Time: 5 minutes

What You’ll Learn

  • Access the Admin UI
  • View real-time request logs
  • Monitor server metrics
  • Manage fixtures with drag-and-drop
  • Configure latency and fault injection
  • Search and filter logs

Prerequisites

  • MockForge installed and running
  • A basic understanding of MockForge concepts

Step 1: Start MockForge with Admin UI

The Admin UI runs on its own port, separate from the mock HTTP server:

mockforge serve --admin --admin-port 9080 --http-port 3000

Access at: http://localhost:9080

Step 2: Access the Dashboard

Open your browser and navigate to http://localhost:9080.

You’ll see the Dashboard with:

Server Status Section

  • HTTP Server: Running on port 3000
  • WebSocket Server: Status and port
  • gRPC Server: Status and port
  • Uptime: How long the server has been running

Quick Stats

  • Total Requests: Request counter
  • Active Connections: Current open connections
  • Average Response Time: Performance metrics
  • Error Rate: Failed requests percentage

Recent Activity

  • Last 10 requests with timestamps, methods, paths, and status codes

Step 3: View Live Logs

Click on the “Logs” tab in the navigation.

Features:

  • Real-time updates: Logs stream via Server-Sent Events (SSE)
  • Color-coded levels: INFO (blue), WARN (yellow), ERROR (red)
  • Request details: Method, path, status code, response time
  • Search: Filter logs by keyword
  • Auto-scroll: Automatically scroll to newest logs

Try It:

  1. Keep the logs tab open
  2. In another terminal, send a request:
    curl http://localhost:3000/users
    
  3. Watch the log appear instantly in the UI!

Use the search box to filter:

  • Search by path: /users
  • Search by method: POST
  • Search by status: 404
  • Search by error message: validation failed

Step 4: Explore Metrics

Click on the “Metrics” tab.

Available Metrics:

  • Request Rate: Requests per second over time
  • Response Times: P50, P95, P99 latencies
  • Status Code Distribution: 2xx, 4xx, 5xx breakdown
  • Endpoint Performance: Slowest endpoints
  • Error Trends: Error rates over time

Use Cases:

  • Performance testing: Monitor response times under load
  • Debugging: Identify which endpoints are failing
  • Capacity planning: See throughput limits

Step 5: Manage Fixtures

Click on the “Fixtures” tab.

What are Fixtures?

Fixtures are saved mock scenarios - collections of requests and expected responses for testing.

Tree View Interface:

📁 Fixtures
  📁 User Management
    ✅ Create User - Happy Path
    ✅ Create User - Validation Error
    ✅ Get User - Not Found
  📁 Order Processing
    ✅ Create Order
    ✅ Update Order Status

Actions:

  1. Drag and Drop: Reorganize fixtures into folders
  2. Run Fixture: Test a specific scenario
  3. Run Folder: Execute all fixtures in a folder
  4. Export: Download fixtures as JSON
  5. Import: Upload fixture collections

Try It:

  1. Click “New Fixture”
  2. Name it: “Test User Creation”
  3. Configure:
    • Method: POST
    • Path: /users
    • Expected Status: 201
    • Request Body:
      {"name": "Test User", "email": "[email protected]"}
      
  4. Click “Save”
  5. Click “Run” to test it

Step 6: Configure Latency Simulation

Click on the “Configuration” tab, then “Latency”.

Latency Profiles:

MockForge can simulate various network conditions:

ProfileDescriptionLatency
NoneNo artificial delay0ms
FastLocal network10-30ms
NormalGood internet50-150ms
SlowPoor connection300-800ms
Very SlowBad mobile1000-3000ms

Configure:

  1. Select “Slow” profile
  2. Click “Apply”
  3. Test an endpoint:
    time curl http://localhost:3000/users
    
  4. Notice the delay!

Per-Endpoint Latency:

You can also configure latency for specific endpoints:

# In your config file
http:
  latency:
    enabled: true
    default_profile: normal
    endpoint_overrides:
      "POST /orders": slow       # Simulate slow order processing
      "GET /products": fast      # Fast product catalog

Step 7: Enable Fault Injection

Still in the “Configuration” tab, click “Fault Injection”.

Fault Types:

  • Random Failures: Randomly return 500 errors
  • Timeouts: Simulate request timeouts
  • Malformed Responses: Return invalid JSON
  • Connection Drops: Close connections unexpectedly

Configure:

  1. Enable Fault Injection: Toggle ON
  2. Error Rate: Set to 20% (1 in 5 requests fails)
  3. Fault Type: Select “Random Failures”
  4. Click “Apply”

Test It:

# Run this multiple times - some will fail!
for i in {1..10}; do
  curl http://localhost:3000/users
  echo ""
done

You’ll see some requests return 500 errors, simulating an unreliable backend.

Step 8: Search Across Services

Click on the “Search” tab.

Search across:

  • Service names
  • Endpoint paths
  • Request/response bodies
  • Log messages
  • Configuration values

Try It:

  1. Search for users - finds all user-related endpoints
  2. Search for POST - finds all POST endpoints
  3. Search for validation - finds validation errors in logs

Step 9: Proxy Configuration (Advanced)

Click “Configuration” → “Proxy”.

Hybrid Mode:

MockForge can act as a proxy, forwarding unknown requests to a real backend:

  1. Enable Proxy: Toggle ON
  2. Target URL: https://api.example.com
  3. Fallback Mode: “Forward unknown requests”
  4. Click “Apply”

Now:

  • Mocked endpoints return mock data
  • Unknown endpoints are forwarded to the real API
  • Perfect for gradual migration!

Common Workflows

Workflow 1: Debug a Failing Test

  1. Open Logs tab
  2. Enable “Error Only” filter
  3. Run your failing test
  4. Find the error in real-time
  5. Copy the request details
  6. Fix your test or mock configuration

Workflow 2: Create Test Fixtures

  1. Run your application manually (e.g., click through the UI)
  2. Admin UI captures all requests in Logs
  3. Click “Save as Fixture” on interesting requests
  4. Organize fixtures into folders
  5. Run fixtures as smoke tests before deployment

Workflow 3: Performance Testing

  1. Clear metrics (Metrics → “Reset”)
  2. Run load test against MockForge
  3. Monitor Metrics tab in real-time
  4. Identify performance bottlenecks
  5. Adjust mock configuration for better performance

Workflow 4: Demo Preparation

  1. Fixtures: Create realistic demo scenarios
  2. Latency: Set to “Fast” for smooth demos
  3. Fault Injection: Disable to prevent unexpected errors
  4. Logs: Keep open to show real-time activity

Keyboard Shortcuts

ShortcutAction
Ctrl+KOpen search
Ctrl+LJump to logs
Ctrl+MJump to metrics
Ctrl+RRefresh dashboard
EscClose modals

Troubleshooting

Admin UI not loading?

  • Check that the admin port (9080) isn’t blocked
  • Verify MockForge is running with --admin flag
  • Check browser console for JavaScript errors

Logs not updating?

  • Ensure Server-Sent Events (SSE) aren’t blocked by your browser or proxy
  • Try refreshing the page
  • Check that /__mockforge/logs endpoint is accessible

Fixtures not saving?

  • Verify you have write permissions to the MockForge data directory
  • Check disk space availability
  • Review logs for error messages

What’s Next?


Pro Tip: Use browser bookmarks for quick access:

  • http://localhost:9080/ - Dashboard
  • http://localhost:9080/?tab=logs - Jump directly to logs
  • http://localhost:9080/?tab=metrics - Jump directly to metrics

Plugin Starter Guide

This guide walks you through creating your first MockForge plugin from scratch. You’ll learn how to scaffold a plugin project, implement plugin functionality, build it, and use it in MockForge.

Overview

MockForge plugins extend the platform’s capabilities through a WebAssembly-based plugin system. Plugins can:

  • Add custom template functions
  • Implement custom authentication logic
  • Generate dynamic responses
  • Connect to external data sources
  • Trigger webhooks
  • Add chaos engineering patterns

Plugin Types

MockForge supports several plugin types:

TypeDescriptionUse Case
templateCustom template functionsAdd domain-specific data generation functions
authAuthentication handlersCustom authentication logic (JWT, OAuth, etc.)
responseResponse generatorsGenerate dynamic responses based on request data
datasourceData source connectorsConnect to external data (CSV, databases, APIs)
webhookWebhook triggersSend outbound HTTP requests to external services
chaosChaos patternsAdd custom failure modes and latency patterns

Step 1: Scaffold Your Plugin

Use the mockforge plugin init command to create a new plugin project:

mockforge plugin init my-custom-plugin --plugin-type template

Options:

  • --plugin-type (default: template): The type of plugin to create
  • --output (optional): Output directory (defaults to plugin name)
  • --force: Overwrite existing directory

Example for different types:

# Template plugin
mockforge plugin init my-template-plugin --plugin-type template

# Authentication plugin
mockforge plugin init my-auth-plugin --plugin-type auth

# Response plugin
mockforge plugin init my-response-plugin --plugin-type response

# Data source plugin
mockforge plugin init my-datasource-plugin --plugin-type datasource

# Webhook plugin
mockforge plugin init my-webhook-plugin --plugin-type webhook

# Chaos plugin
mockforge plugin init my-chaos-plugin --plugin-type chaos

What Gets Created

The command creates a complete plugin project structure:

my-custom-plugin/
├── Cargo.toml          # Rust dependencies and build config
├── plugin.yaml         # Plugin manifest with metadata
├── src/
│   └── lib.rs         # Plugin implementation
├── README.md          # Plugin documentation template
└── .gitignore        # Git ignore file

Step 2: Understand the Plugin Structure

Cargo.toml

The Cargo.toml file defines your plugin’s dependencies:

[package]
name = "my-custom-plugin"
version = "0.1.0"
edition = "2021"

[dependencies]
mockforge-plugin-core = { path = "../../../crates/mockforge-plugin-core" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
async-trait = "0.1"

plugin.yaml

The plugin.yaml file is the plugin manifest:

id: my-custom-plugin
name: My Custom Plugin
version: 0.1.0
description: Description of what this plugin does
author: Your Name
license: MIT OR Apache-2.0

type: template  # template, auth, response, datasource, webhook, chaos

capabilities:
  network:
    allow_http: false
    allowed_hosts: []
  filesystem:
    read_paths: []
    write_paths: []
  resources:
    max_memory_bytes: 10485760  # 10MB
    max_cpu_percent: 50
    max_execution_time_ms: 1000

config_schema:
  type: object
  properties:
    # Plugin-specific configuration

src/lib.rs

The src/lib.rs file contains your plugin implementation. The scaffolded code provides a template based on your plugin type.

Step 3: Implement Your Plugin

Template Plugin Example

Template plugins add custom functions to MockForge’s templating system:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::{
    TemplatePlugin, TemplatePluginConfig, TemplateFunction, 
    FunctionParameter, PluginContext, PluginResult, Result, Value
};
use std::collections::HashMap;

pub struct MyTemplatePlugin {
    config: TemplatePluginConfig,
}

#[async_trait::async_trait]
impl TemplatePlugin for MyTemplatePlugin {
    fn capabilities(&self) -> PluginCapabilities {
        PluginCapabilities {
            network: NetworkPermissions {
                allow_http: false,
                allowed_hosts: vec![],
                max_connections: 10,
            },
            filesystem: FilesystemPermissions {
                read_paths: vec![],
                write_paths: vec![],
                allow_temp_files: false,
            },
            resources: ResourceLimits {
                max_memory_bytes: 10 * 1024 * 1024, // 10MB
                max_cpu_percent: 50,
                max_execution_time_ms: 1000,
                max_concurrent_executions: 5,
            },
            custom: HashMap::new(),
        }
    }

    async fn initialize(&self, _config: &TemplatePluginConfig) -> Result<()> {
        Ok(())
    }

    async fn register_functions(
        &self,
        _context: &PluginContext,
        _config: &TemplatePluginConfig,
    ) -> Result<PluginResult<HashMap<String, TemplateFunction>>> {
        let mut functions = HashMap::new();

        // Register a custom function
        functions.insert(
            "my_custom_function".to_string(),
            TemplateFunction::new(
                "my_custom_function",
                "Does something custom",
                "string"
            )
            .with_parameter(
                FunctionParameter::required("input", "string", "Input value")
            )
            .with_example("{{my_custom_function \"hello\"}}")
            .with_category("custom"),
        );

        Ok(PluginResult::success(functions, 0))
    }

    async fn execute_function(
        &self,
        _context: &PluginContext,
        function_name: &str,
        args: &[Value],
        _config: &TemplatePluginConfig,
    ) -> Result<PluginResult<Value>> {
        match function_name {
            "my_custom_function" => {
                let input = args.get(0)
                    .and_then(|v| v.as_str())
                    .ok_or_else(|| PluginError::execution("Missing input argument"))?;
                
                let result = format!("Processed: {}", input);
                Ok(PluginResult::success(Value::String(result), 0))
            }
            _ => Ok(PluginResult::failure(
                format!("Unknown function: {}", function_name),
                0
            )),
        }
    }

    // ... other required methods
}
}

Response Plugin Example

Response plugins generate custom responses based on request data:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::{
    ResponsePlugin, ResponsePluginConfig, ResponseRequest,
    ResponseData, PluginContext, PluginResult, Result
};
use std::collections::HashMap;

pub struct MyResponsePlugin {
    config: ResponsePluginConfig,
}

#[async_trait::async_trait]
impl ResponsePlugin for MyResponsePlugin {
    fn capabilities(&self) -> PluginCapabilities {
        // Define capabilities
    }

    async fn initialize(&self, _config: &ResponsePluginConfig) -> Result<()> {
        Ok(())
    }

    async fn can_handle(
        &self,
        _context: &PluginContext,
        request: &ResponseRequest,
        _config: &ResponsePluginConfig,
    ) -> Result<PluginResult<bool>> {
        // Determine if this plugin should handle the request
        let should_handle = request.path.starts_with("/api/custom");
        Ok(PluginResult::success(should_handle, 0))
    }

    async fn generate_response(
        &self,
        _context: &PluginContext,
        request: &ResponseRequest,
        _config: &ResponsePluginConfig,
    ) -> Result<PluginResult<ResponseData>> {
        // Generate custom response
        let body = json!({
            "message": "Custom response",
            "path": request.path,
            "method": request.method.as_str(),
        });

        let response_data = ResponseData {
            status_code: 200,
            headers: HashMap::new(),
            body: serde_json::to_vec(&body)?,
            content_type: "application/json".to_string(),
            metadata: HashMap::new(),
            cache_control: None,
            custom: HashMap::new(),
        };

        Ok(PluginResult::success(response_data, 0))
    }

    // ... other required methods
}
}

Webhook Plugin Example

Webhook plugins make outbound HTTP requests:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::{
    ResponsePlugin, ResponsePluginConfig, ResponseRequest,
    ResponseData, PluginContext, PluginResult, Result
};

pub struct MyWebhookPlugin {
    config: ResponsePluginConfig,
    webhook_url: String,
}

#[async_trait::async_trait]
impl ResponsePlugin for MyWebhookPlugin {
    fn capabilities(&self) -> PluginCapabilities {
        PluginCapabilities {
            network: NetworkPermissions {
                allow_http: true,  // Enable network access
                allowed_hosts: vec![
                    self.webhook_url
                        .strip_prefix("https://")
                        .or_else(|| self.webhook_url.strip_prefix("http://"))
                        .and_then(|url| url.split('/').next())
                        .unwrap_or("*")
                        .to_string()
                ],
                max_connections: 10,
            },
            // ... other capabilities
        }
    }

    async fn generate_response(
        &self,
        _context: &PluginContext,
        request: &ResponseRequest,
        _config: &ResponsePluginConfig,
    ) -> Result<PluginResult<ResponseData>> {
        // Generate webhook payload
        let payload = json!({
            "event": "mockforge.request",
            "path": request.path,
            "method": request.method.as_str(),
            "timestamp": chrono::Utc::now().to_rfc3339(),
        });

        // In a real implementation, make HTTP request here
        // For security, this requires network capabilities

        let response_data = ResponseData {
            status_code: 200,
            headers: HashMap::new(),
            body: serde_json::to_vec(&payload)?,
            content_type: "application/json".to_string(),
            metadata: HashMap::new(),
            cache_control: None,
            custom: HashMap::new(),
        };

        Ok(PluginResult::success(response_data, 0))
    }

    // ... other required methods
}
}

Step 4: Build Your Plugin

Build your plugin for WebAssembly:

cd my-custom-plugin
cargo build --target wasm32-wasi --release

The compiled .wasm file will be in:

target/wasm32-wasi/release/my_custom_plugin.wasm

Step 5: Test Your Plugin

Unit Tests

Add tests to your plugin:

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_my_custom_function() {
        let plugin = MyTemplatePlugin::new();
        let config = TemplatePluginConfig::default();
        
        plugin.initialize(&config).await.unwrap();
        
        let functions = plugin.register_functions(
            &PluginContext::default(),
            &config
        ).await.unwrap();
        
        assert!(functions.result.contains_key("my_custom_function"));
    }
}
}

Run tests:

cargo test

Integration Testing

Test your plugin with MockForge:

  1. Install the plugin:

    mockforge plugin install ./my-custom-plugin
    
  2. List installed plugins:

    mockforge plugin list
    
  3. Use in mockforge.yaml:

    plugins:
      - id: my-custom-plugin
        type: template
        config:
          # Plugin-specific config
    
  4. Start MockForge:

    mockforge serve
    
  5. Test the plugin:

    # For template plugins, use in templates
    curl http://localhost:3000/api/test
    

Step 6: Learn from Examples

The MockForge repository includes comprehensive example plugins you can learn from:

Template Plugins

template-advanced/ - Advanced template functions:

  • Mathematical operations (sum, average)
  • Collection operations (group_by, sort)
  • Date/time formatting
  • UUID generation

Inspect:

cd examples/plugins/template-advanced/
cat src/lib.rs
cat README.md

template-custom/ - Domain-specific functions:

  • Business data generation
  • Custom formatting
  • Domain-specific helpers

Response Plugins

webhook-example/ - Webhook functionality:

  • Outbound HTTP requests
  • Payload signing
  • Event-based triggering

Inspect:

cd examples/plugins/webhook-example/
cat src/lib.rs
cat plugin.yaml

Authentication Plugins

auth-basic/ - HTTP Basic Authentication:

  • Credential validation
  • Realm configuration
  • Secure password handling

Inspect:

cd examples/plugins/auth-basic/
cat src/lib.rs

Data Source Plugins

datasource-csv/ - CSV data source:

  • CSV file parsing
  • Data querying
  • Type inference

Inspect:

cd examples/plugins/datasource-csv/
cat src/lib.rs

Complete Example: Creating a Template Plugin

Let’s create a complete template plugin step-by-step:

1. Scaffold the Plugin

mockforge plugin init currency-formatter --plugin-type template
cd currency-formatter

2. Implement the Plugin

Edit src/lib.rs:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::{
    TemplatePlugin, TemplatePluginConfig, TemplateFunction,
    FunctionParameter, PluginContext, PluginResult, Result, Value
};
use std::collections::HashMap;

pub struct CurrencyFormatterPlugin {
    config: TemplatePluginConfig,
}

#[async_trait::async_trait]
impl TemplatePlugin for CurrencyFormatterPlugin {
    fn capabilities(&self) -> PluginCapabilities {
        PluginCapabilities {
            network: NetworkPermissions {
                allow_http: false,
                allowed_hosts: vec![],
                max_connections: 10,
            },
            filesystem: FilesystemPermissions {
                read_paths: vec![],
                write_paths: vec![],
                allow_temp_files: false,
            },
            resources: ResourceLimits {
                max_memory_bytes: 5 * 1024 * 1024, // 5MB
                max_cpu_percent: 50,
                max_execution_time_ms: 500,
                max_concurrent_executions: 5,
            },
            custom: HashMap::new(),
        }
    }

    async fn initialize(&self, _config: &TemplatePluginConfig) -> Result<()> {
        Ok(())
    }

    async fn register_functions(
        &self,
        _context: &PluginContext,
        _config: &TemplatePluginConfig,
    ) -> Result<PluginResult<HashMap<String, TemplateFunction>>> {
        let mut functions = HashMap::new();

        functions.insert(
            "format_currency".to_string(),
            TemplateFunction::new(
                "format_currency",
                "Format a number as currency",
                "string"
            )
            .with_parameter(
                FunctionParameter::required("amount", "number", "Amount to format")
            )
            .with_parameter(
                FunctionParameter::optional("currency", "string", "Currency code (default: USD)")
            )
            .with_example("{{format_currency 1234.56 \"USD\"}}")
            .with_category("formatting"),
        );

        Ok(PluginResult::success(functions, 0))
    }

    async fn execute_function(
        &self,
        _context: &PluginContext,
        function_name: &str,
        args: &[Value],
        _config: &TemplatePluginConfig,
    ) -> Result<PluginResult<Value>> {
        match function_name {
            "format_currency" => {
                let amount = args.get(0)
                    .and_then(|v| v.as_f64())
                    .ok_or_else(|| PluginError::execution("Amount must be a number"))?;
                
                let currency = args.get(1)
                    .and_then(|v| v.as_str())
                    .unwrap_or("USD");
                
                let formatted = match currency {
                    "USD" => format!("${:.2}", amount),
                    "EUR" => format!("€{:.2}", amount),
                    "GBP" => format!("£{:.2}", amount),
                    _ => format!("{:.2} {}", amount, currency),
                };
                
                Ok(PluginResult::success(Value::String(formatted), 0))
            }
            _ => Ok(PluginResult::failure(
                format!("Unknown function: {}", function_name),
                0
            )),
        }
    }

    async fn get_data_source(
        &self,
        _context: &PluginContext,
        _data_source: &str,
        _config: &TemplatePluginConfig,
    ) -> Result<PluginResult<Value>> {
        Ok(PluginResult::failure("No data sources available".to_string(), 0))
    }

    fn validate_config(&self, _config: &TemplatePluginConfig) -> Result<()> {
        Ok(())
    }

    fn available_data_sources(&self) -> Vec<String> {
        vec![]
    }

    async fn cleanup(&self) -> Result<()> {
        Ok(())
    }
}

// Export the plugin
#[no_mangle]
pub extern "C" fn create_plugin() -> *mut dyn TemplatePlugin {
    Box::into_raw(Box::new(CurrencyFormatterPlugin {
        config: TemplatePluginConfig::default(),
    }))
}

#[no_mangle]
pub extern "C" fn destroy_plugin(plugin: *mut dyn TemplatePlugin) {
    unsafe {
        drop(Box::from_raw(plugin));
    }
}
}

3. Update plugin.yaml

id: currency-formatter
name: Currency Formatter
version: 0.1.0
description: Format numbers as currency strings
author: Your Name
license: MIT OR Apache-2.0

type: template

capabilities:
  network:
    allow_http: false
  filesystem:
    read_paths: []
    write_paths: []
  resources:
    max_memory_bytes: 5242880  # 5MB
    max_cpu_percent: 50
    max_execution_time_ms: 500

4. Build and Test

# Build
cargo build --target wasm32-wasi --release

# Test
cargo test

# Install
mockforge plugin install .

# Use in mockforge.yaml

5. Use in Templates

# mockforge.yaml
responses:
  - path: /api/products
    method: GET
    body: |
      {
        "products": [
          {
            "name": "Product 1",
            "price": "{{format_currency 29.99 \"USD\"}}"
          }
        ]
      }

Best Practices

1. Error Handling

Always handle errors gracefully:

#![allow(unused)]
fn main() {
async fn execute_function(
    &self,
    _context: &PluginContext,
    function_name: &str,
    args: &[Value],
    _config: &TemplatePluginConfig,
) -> Result<PluginResult<Value>> {
    match function_name {
        "my_function" => {
            let input = args.get(0)
                .and_then(|v| v.as_str())
                .ok_or_else(|| PluginError::execution("Missing required argument"))?;
            
            // Your logic here
            Ok(PluginResult::success(Value::String(result), 0))
        }
        _ => Ok(PluginResult::failure(
            format!("Unknown function: {}", function_name),
            0
        )),
    }
}
}

2. Resource Limits

Set appropriate resource limits:

#![allow(unused)]
fn main() {
resources: ResourceLimits {
    max_memory_bytes: 10 * 1024 * 1024,  // 10MB
    max_cpu_percent: 50,
    max_execution_time_ms: 1000,  // 1 second
    max_concurrent_executions: 5,
}
}

3. Security

  • Only request necessary capabilities
  • Validate all inputs
  • Sanitize outputs
  • Use allowed_hosts for network access

4. Documentation

  • Document all functions in register_functions
  • Provide examples in function metadata
  • Include usage examples in README.md

Troubleshooting

Plugin Won’t Build

Issue: Compilation errors

Solution:

  • Check that all dependencies are in Cargo.toml
  • Ensure you’re using the correct Rust edition (2021)
  • Verify mockforge-plugin-core path is correct

Plugin Not Loading

Issue: Plugin fails to load in MockForge

Solution:

  • Check plugin.yaml syntax
  • Verify plugin type matches implementation
  • Check capability requirements
  • Review MockForge logs for errors

Function Not Found

Issue: Template function not available

Solution:

  • Ensure function is registered in register_functions
  • Check function name matches exactly
  • Verify plugin is installed and enabled
  • Check plugin configuration

Next Steps

  1. Explore Example Plugins: Study the example plugins in examples/plugins/
  2. Read Plugin API Docs: See crates/mockforge-plugin-core/src/ for trait definitions
  3. Join the Community: Share your plugins and get feedback
  4. Contribute: Submit your plugins to the marketplace

IDE Extension Guide

This guide walks you through installing, configuring, and using the MockForge VS Code extension to enhance your development workflow with inline mock previews, config validation, and seamless playground integration.

Overview

The MockForge VS Code extension brings the power of MockForge directly into your editor, providing:

  • Peek Mock Response: Hover over API endpoints to see mock responses inline
  • Config Validation: Real-time validation of mockforge.yaml files with inline errors
  • Mocks Explorer: Visual tree view of all mocks with real-time updates
  • Playground Integration: Quick access to MockForge Playground from hover tooltips
  • Mock Management: Create, edit, enable/disable, and delete mocks from VS Code

Installation

From VS Code Marketplace

  1. Open VS Code
  2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
  3. Search for “MockForge”
  4. Click Install

Or install via command line:

code --install-extension saasy-solutions.mockforge-vscode

From VSIX File

If you have a .vsix file:

code --install-extension mockforge-vscode-0.1.0.vsix

Verify Installation

After installation, you should see:

  • MockForge icon in the Activity Bar (left sidebar)
  • MockForge commands available in Command Palette (Ctrl+Shift+P / Cmd+Shift+P)

Configuration

Basic Setup

Configure the extension in VS Code settings:

  1. Open Settings (Ctrl+, / Cmd+,)
  2. Search for “mockforge”
  3. Configure the following:
{
  "mockforge.serverUrl": "http://localhost:3000",
  "mockforge.autoConnect": true,
  "mockforge.showNotifications": true,
  "mockforge.inlinePreview.enabled": true
}

Settings:

  • mockforge.serverUrl: MockForge server URL (default: http://localhost:3000)
  • mockforge.autoConnect: Automatically connect on startup (default: true)
  • mockforge.showNotifications: Show notifications for mock changes (default: true)
  • mockforge.inlinePreview.enabled: Enable inline preview of mock responses (default: true)

Workspace Settings

For project-specific configuration, add to .vscode/settings.json:

{
  "mockforge.serverUrl": "http://localhost:3000",
  "mockforge.autoConnect": true
}

Feature 1: Peek Mock Response

The peek response feature shows mock responses when you hover over API endpoint references in your code.

How It Works

  1. Hover over an endpoint in your code (JavaScript, TypeScript, or YAML)
  2. See the mock response in a tooltip with headers and body
  3. Click “Open in Playground” to test the endpoint interactively

Supported Patterns

The extension detects endpoints in various patterns:

JavaScript/TypeScript:

// fetch() calls
const response = await fetch('/api/users');

// axios calls
const data = await axios.get('/api/products');

// http client calls
const result = await http.get('/api/orders');

YAML Config Files:

# mockforge.yaml
responses:
  - path: /api/users
    method: GET

Example Usage

Before (without extension):

  • You write: fetch('/api/users')
  • You have no idea what the response looks like
  • You need to run the app or check documentation

After (with extension):

  • You write: fetch('/api/users')
  • You hover over the endpoint
  • You see:
    {
      "users": [
        {
          "id": 1,
          "name": "John Doe",
          "email": "[email protected]"
        }
      ]
    }
    
  • You click “Open in Playground” to test it

Configuration

Enable/disable peek response:

{
  "mockforge.inlinePreview.enabled": true
}

Troubleshooting

Preview not showing:

  1. Ensure MockForge server is running
  2. Check that mockforge.inlinePreview.enabled is true
  3. Verify the endpoint path matches a configured mock
  4. Check VS Code output panel for errors

Preview shows “No mock configured”:

  • The endpoint doesn’t have a mock configured
  • Click “Open in Playground” to create one
  • Or add a mock in mockforge.yaml

Feature 2: Config Validation

Get real-time validation for your mockforge.yaml files with inline error reporting.

How It Works

  1. Open mockforge.yaml in VS Code
  2. See inline errors for invalid configuration
  3. Get helpful messages for missing fields, type mismatches, and invalid values
  4. Auto-detect schema type based on file name and location

Supported Config Types

The extension validates:

  • Main config: mockforge.yaml, mockforge.yml, mockforge.json
  • Blueprint config: blueprint.yaml
  • Reality config: Files in reality/ directory or reality*.yaml
  • Persona config: Files in personas/ directory

Example Validation

Invalid Configuration:

# mockforge.yaml
reality:
  level: invalid_level  # ❌ Error shown here

Error Message:

Invalid reality level: invalid_level. Valid values: static, light, moderate, high, chaos

Valid Configuration:

# mockforge.yaml
reality:
  level: moderate  # ✅ No errors

Schema Generation

The extension can auto-generate schemas:

  1. Run schema generation:

    mockforge schema generate
    
  2. Schemas are saved to schemas/ directory

  3. Extension auto-detects schemas in:

    • schemas/ directory
    • .mockforge/ directory
    • Project root

Validation Features

  • Real-time validation: Errors appear as you type
  • Accurate positions: Line and column numbers for errors
  • Helpful messages: Clear descriptions of what’s wrong
  • Auto-detection: Automatically detects schema type
  • Multiple schemas: Supports all MockForge config types

Troubleshooting

Validation not working:

  1. Ensure you have a mockforge.yaml file open
  2. Check that schemas are available:
    • Look for schemas/ directory
    • Or run mockforge schema generate
  3. Check VS Code output panel for validation errors

Schema not found:

  • Run mockforge schema generate to create schemas
  • Or manually place schemas in schemas/ directory

Feature 3: Mocks Explorer

Visual tree view of all your mocks with real-time WebSocket updates.

Accessing Mocks Explorer

  1. Click MockForge icon in Activity Bar (left sidebar)
  2. Open “Mocks Explorer” view
  3. Browse all mocks in a tree view

Features

  • Color-coded by HTTP method: GET (blue), POST (green), PUT (orange), DELETE (red)
  • Real-time updates: Changes sync automatically via WebSocket
  • Context menu actions:
    • Edit Mock
    • Delete Mock
    • Toggle Mock (enable/disable)
    • View Details

Using Mocks Explorer

View Mocks:

  1. Open Mocks Explorer
  2. Click on a mock to see details
  3. Expand folders to see grouped mocks

Edit Mock:

  1. Right-click on a mock
  2. Select “Edit Mock”
  3. Modify JSON configuration
  4. Save to update

Toggle Mock:

  1. Right-click on a mock
  2. Select “Toggle Mock”
  3. Mock is enabled/disabled

Delete Mock:

  1. Right-click on a mock
  2. Select “Delete Mock”
  3. Confirm deletion

Feature 4: Playground Integration

Quick access to MockForge Playground from hover tooltips and commands.

From Hover Tooltip

  1. Hover over an endpoint in your code
  2. See the tooltip with mock response
  3. Click “Open in Playground” link
  4. Playground opens in browser with endpoint pre-filled

From Command Palette

  1. Open Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
  2. Type “MockForge: Open Playground”
  3. Enter endpoint details (method and path)
  4. Playground opens in browser

Playground URL Format

The extension constructs URLs like:

http://localhost:3000/admin/#/playground?method=GET&path=/api/users

For standalone admin UI:

http://localhost:9080/#/playground?method=GET&path=/api/users

Feature 5: Server Control

Monitor your MockForge server status and statistics.

Accessing Server Control

  1. Click MockForge icon in Activity Bar
  2. Open “Server Control” view
  3. View server statistics

Information Displayed

  • Connection status: Connected / Disconnected
  • Server version: MockForge version
  • Server port: Port number
  • Uptime: How long server has been running
  • Request count: Total requests processed
  • Active mocks: Number of active mocks

Quick Actions

  • Start Server: Start MockForge server
  • Stop Server: Stop MockForge server
  • Restart Server: Restart MockForge server

Complete Workflow Example

Let’s walk through a complete workflow using all features:

1. Install Extension

code --install-extension saasy-solutions.mockforge-vscode

2. Start MockForge Server

mockforge serve

3. Configure Extension

Add to .vscode/settings.json:

{
  "mockforge.serverUrl": "http://localhost:3000",
  "mockforge.autoConnect": true,
  "mockforge.inlinePreview.enabled": true
}

4. Create Mock Config

Create mockforge.yaml:

http:
  port: 3000

responses:
  - path: /api/users
    method: GET
    body:
      users:
        - id: 1
          name: "John Doe"
          email: "[email protected]"
        - id: 2
          name: "Jane Smith"
          email: "[email protected]"

5. Use Peek Response

In your code:

// Hover over this endpoint to see the mock response
const response = await fetch('/api/users');

Hover tooltip shows:

{
  "users": [
    {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]"
    },
    {
      "id": 2,
      "name": "Jane Smith",
      "email": "[email protected]"
    }
  ]
}

6. Open in Playground

Click “Open in Playground” in the hover tooltip to test the endpoint interactively.

7. Validate Config

Edit mockforge.yaml and see real-time validation:

reality:
  level: moderate  # ✅ Valid
reality:
  level: invalid  # ❌ Error: Invalid reality level

8. Manage Mocks

  • Open Mocks Explorer
  • View all mocks
  • Edit, delete, or toggle mocks
  • See real-time updates

Advanced Usage

Custom Server URL

For different environments:

{
  "mockforge.serverUrl": "http://localhost:3001"
}

Disable Auto-Connect

If you want to connect manually:

{
  "mockforge.autoConnect": false
}

Disable Notifications

To reduce notification noise:

{
  "mockforge.showNotifications": false
}

Disable Peek Response

If you don’t want inline previews:

{
  "mockforge.inlinePreview.enabled": false
}

Troubleshooting

Extension Not Connecting

Symptoms:

  • Mocks Explorer shows “Disconnected”
  • Peek response doesn’t work
  • Server Control shows disconnected

Solutions:

  1. Check that MockForge server is running
  2. Verify mockforge.serverUrl setting is correct
  3. Check VS Code output panel for connection errors
  4. Try restarting the extension: Command Palette → “MockForge: Restart Extension”

Validation Not Working

Symptoms:

  • No inline errors in mockforge.yaml
  • Validation errors not showing

Solutions:

  1. Ensure you have a mockforge.yaml file open
  2. Check that schemas are available:
    • Look for schemas/ directory
    • Or run mockforge schema generate
  3. Check VS Code output panel for validation errors
  4. Try reloading the window: Command Palette → “Developer: Reload Window”

Peek Response Not Showing

Symptoms:

  • Hovering over endpoints doesn’t show tooltip
  • Tooltip shows “No mock configured”

Solutions:

  1. Ensure mockforge.inlinePreview.enabled is true
  2. Check that MockForge server is connected
  3. Verify the endpoint path matches a configured mock
  4. Try hovering over different endpoint patterns
  5. Check VS Code output panel for errors

Schema Not Found

Symptoms:

  • Validation says “Schema not available”
  • Auto-detection fails

Solutions:

  1. Run mockforge schema generate to create schemas
  2. Ensure schemas are in schemas/ directory
  3. Check that schema file names match expected patterns
  4. Verify schema JSON is valid

Keyboard Shortcuts

The extension doesn’t define custom keyboard shortcuts by default, but you can add them:

{
  "key": "ctrl+shift+m",
  "command": "mockforge.refreshMocks"
}

Commands

All extension commands are available via Command Palette (Ctrl+Shift+P / Cmd+Shift+P):

  • MockForge: Refresh Mocks - Refresh mocks list
  • MockForge: Create Mock - Create a new mock
  • MockForge: Open Playground - Open playground in browser
  • MockForge: Show Logs - Show extension logs
  • MockForge: Restart Extension - Restart the extension

Best Practices

1. Keep Server Running

For best experience, keep MockForge server running while developing.

2. Generate Schemas

Run mockforge schema generate to enable config validation.

3. Use Workspace Settings

Configure extension per-project in .vscode/settings.json.

4. Enable Auto-Connect

Set mockforge.autoConnect: true for seamless workflow.

5. Check Output Panel

If something doesn’t work, check VS Code output panel for errors.

Next Steps

  1. Install the extension and configure it
  2. Start MockForge server and connect
  3. Try peek response by hovering over endpoints
  4. Validate your config by editing mockforge.yaml
  5. Explore Mocks Explorer to manage your mocks
  6. Use Playground to test endpoints interactively

Add a Custom Plugin

Goal: Extend MockForge with a plugin to add custom authentication or data generation functionality.

Time: 10 minutes

What You’ll Learn

  • Install a plugin from a remote source
  • Install a plugin from a local file
  • Use a plugin in your mock configuration
  • Create a simple custom plugin
  • Test and debug plugins

Prerequisites

  • MockForge installed (Installation Guide)
  • Basic understanding of MockForge configuration
  • (Optional) Rust toolchain for building custom plugins

Step 1: Install a Pre-Built Plugin

MockForge comes with example plugins you can install immediately.

Install the JWT Authentication Plugin

# Install from the examples directory (if building from source)
mockforge plugin install examples/plugins/auth-jwt

# Or install from a URL (when published)
mockforge plugin install https://github.com/SaaSy-Solutions/mockforge/releases/download/v1.0.0/auth-jwt-plugin.wasm

Verify Installation

mockforge plugin list

Output:

Installed Plugins:
  - auth-jwt (v1.0.0)
    Description: JWT authentication and token generation
    Author: MockForge Team

Step 2: Use the Plugin in Your Configuration

Create a config file that uses the JWT plugin:

api-with-auth.yaml:

http:
  port: 3000
  response_template_expand: true

  # Load the plugin
  plugins:
    - name: auth-jwt
      config:
        secret: "my-super-secret-key"
        algorithm: HS256
        expiry: 3600  # 1 hour

  routes:
    # Login endpoint - generates JWT token
    - path: /auth/login
      method: POST
      response:
        status: 200
        headers:
          Content-Type: application/json
        body: |
          {
            "token": "{{plugin:auth-jwt:generate_token({{request.body.username}})}}",
            "expiresIn": 3600
          }

    # Protected endpoint - validates JWT
    - path: /users/me
      method: GET
      middleware:
        - plugin: auth-jwt
          action: validate_token
      response:
        status: 200
        body: |
          {
            "id": "{{uuid}}",
            "username": "{{plugin:auth-jwt:get_claim(username)}}",
            "email": "{{plugin:auth-jwt:get_claim(email)}}"
          }

Step 3: Test the Plugin

Start the server:

mockforge serve --config api-with-auth.yaml

Login and Get Token

curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "secret123"}'

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFsaWNlIiwiZXhwIjoxNzA5NTY3ODkwfQ.signature",
  "expiresIn": 3600
}

Use Token to Access Protected Endpoint

# Save the token
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

# Access protected endpoint
curl http://localhost:3000/users/me \
  -H "Authorization: Bearer $TOKEN"

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "username": "alice",
  "email": "[email protected]"
}

Try Without Token (Should Fail)

curl http://localhost:3000/users/me

Response:

{
  "error": "Unauthorized",
  "message": "Missing or invalid JWT token"
}

Step 4: Install the Template Crypto Plugin

Let’s install another plugin for encryption in templates:

mockforge plugin install examples/plugins/template-crypto

crypto-config.yaml:

http:
  port: 3000
  response_template_expand: true

  plugins:
    - name: template-crypto
      config:
        default_algorithm: aes-256-gcm

  routes:
    - path: /encrypt
      method: POST
      response:
        status: 200
        body: |
          {
            "encrypted": "{{plugin:template-crypto:encrypt({{request.body.message}})}}",
            "algorithm": "aes-256-gcm"
          }

    - path: /decrypt
      method: POST
      response:
        status: 200
        body: |
          {
            "decrypted": "{{plugin:template-crypto:decrypt({{request.body.encrypted}})}}"
          }

Test it:

# Encrypt a message
curl -X POST http://localhost:3000/encrypt \
  -H "Content-Type: application/json" \
  -d '{"message": "secret data"}'

# Decrypt the result
curl -X POST http://localhost:3000/decrypt \
  -H "Content-Type: application/json" \
  -d '{"encrypted": "base64-encrypted-string"}'

Step 5: Create a Simple Custom Plugin

Let’s create a custom plugin that generates fake company data.

Project Structure

mkdir my-company-plugin
cd my-company-plugin
cargo init --lib

Cargo.toml:

[package]
name = "company-data-plugin"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
mockforge-plugin-api = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
fake = { version = "2.9", features = ["derive"] }

src/lib.rs:

#![allow(unused)]
fn main() {
use mockforge_plugin_api::{Plugin, PluginContext, PluginResult};
use fake::{Fake, faker::company::en::*};
use serde_json::json;

pub struct CompanyDataPlugin;

impl Plugin for CompanyDataPlugin {
    fn name(&self) -> &str {
        "company-data"
    }

    fn version(&self) -> &str {
        "0.1.0"
    }

    fn execute(&self, ctx: &PluginContext) -> PluginResult {
        match ctx.action.as_str() {
            "generate_company" => {
                let company_name: String = CompanyName().fake();
                let industry: String = Industry().fake();
                let buzzword: String = Buzzword().fake();

                Ok(json!({
                    "name": company_name,
                    "industry": industry,
                    "tagline": buzzword,
                    "founded": (1950..2024).fake::<i32>(),
                    "employees": (10..10000).fake::<i32>()
                }))
            }
            "generate_tagline" => {
                Ok(json!({
                    "tagline": Buzzword().fake::<String>()
                }))
            }
            _ => Err(format!("Unknown action: {}", ctx.action))
        }
    }
}

mockforge_plugin_api::export_plugin!(CompanyDataPlugin);
}

Build the Plugin

cargo build --release --target wasm32-unknown-unknown

The compiled plugin will be at:

target/wasm32-unknown-unknown/release/company_data_plugin.wasm

Step 6: Install and Use Your Custom Plugin

# Install from local file
mockforge plugin install ./target/wasm32-unknown-unknown/release/company_data_plugin.wasm

company-api.yaml:

http:
  port: 3000
  response_template_expand: true

  plugins:
    - name: company-data

  routes:
    - path: /companies
      method: GET
      response:
        status: 200
        body: |
          [
            {{plugin:company-data:generate_company()}},
            {{plugin:company-data:generate_company()}},
            {{plugin:company-data:generate_company()}}
          ]

    - path: /tagline
      method: GET
      response:
        status: 200
        body: "{{plugin:company-data:generate_tagline()}}"

Test it:

mockforge serve --config company-api.yaml

# Generate fake companies
curl http://localhost:3000/companies

Response:

[
  {
    "name": "Acme Corporation",
    "industry": "Technology",
    "tagline": "Innovative solutions for tomorrow",
    "founded": 1985,
    "employees": 2500
  },
  {
    "name": "GlobalTech Industries",
    "industry": "Manufacturing",
    "tagline": "Building the future",
    "founded": 2001,
    "employees": 850
  },
  {
    "name": "DataSync Solutions",
    "industry": "Software",
    "tagline": "Connecting businesses worldwide",
    "founded": 2015,
    "employees": 120
  }
]

Step 7: Plugin Management Commands

List Installed Plugins

mockforge plugin list

Get Plugin Info

mockforge plugin info auth-jwt

Update a Plugin

mockforge plugin update auth-jwt

Uninstall a Plugin

mockforge plugin uninstall company-data

Install with Version Pinning

# From Git with version tag
mockforge plugin install https://github.com/user/plugin#v1.2.0

# From URL with checksum verification
mockforge plugin install https://example.com/plugin.wasm --checksum sha256:abc123...

Common Plugin Use Cases

Use CasePlugin TypeExample
AuthenticationMiddlewareJWT, OAuth2, API keys
Data GenerationTemplate functionFaker, custom generators
Data TransformationResponse modifierFormat converters, encryption
External IntegrationData sourceDatabase, CSV files, APIs
Custom ValidationRequest validatorBusiness rule enforcement
Rate LimitingMiddlewareToken bucket, sliding window

Plugin Security

MockForge plugins run in a WebAssembly sandbox with:

  • Memory isolation: Plugins can’t access host memory
  • Resource limits: CPU and memory usage capped
  • No network access: Plugins can’t make external requests (unless explicitly allowed)
  • File system restrictions: Limited file access

Configure Plugin Permissions

config.yaml:

plugins:
  security:
    max_memory_mb: 50
    max_execution_ms: 1000
    allow_network: false
    allow_file_access: false

  plugins:
    - name: auth-jwt
      permissions:
        network: false
        file_read: false

    - name: db-connector
      permissions:
        network: true  # Needs network for DB connection
        file_read: true

Debugging Plugins

Enable Plugin Debug Logs

MOCKFORGE_LOG_LEVEL=debug mockforge serve --config api-with-auth.yaml

Test Plugin in Isolation

# Runs the plugin project's own test suite (cargo test), from its project directory
mockforge-plugin test --path ./my-plugin

There is no built-in plugin benchmarking command.

Troubleshooting

Plugin not found after installation?

# Check plugin directory
mockforge plugin list --detailed

# Reinstall
mockforge plugin install ./path/to/plugin.wasm --force

Plugin execution fails?

  • Check plugin logs with MOCKFORGE_LOG_LEVEL=debug
  • Verify plugin configuration syntax
  • Test plugin in isolation with mockforge-plugin test

Plugin build fails?

# Ensure wasm target is installed
rustup target add wasm32-unknown-unknown

# Clean and rebuild
cargo clean
cargo build --release --target wasm32-unknown-unknown

What’s Next?


Pro Tip: Plugins can be version-controlled and shared with your team. Commit the .wasm file or the source code to Git, and everyone can use the same custom functionality!

HTTP Mocking

MockForge provides comprehensive HTTP API mocking capabilities with OpenAPI specification support, dynamic response generation, and advanced request matching. This guide covers everything you need to create realistic REST API mocks.

OpenAPI Integration

MockForge uses OpenAPI (formerly Swagger) specifications as the foundation for HTTP API mocking. This industry-standard approach ensures your mocks accurately reflect real API contracts.

Loading OpenAPI Specifications

# Load from JSON file
mockforge serve --spec api-spec.json --http-port 3000

# Load from YAML file
mockforge serve --spec api-spec.yaml --http-port 3000

# Load from URL
mockforge serve --spec https://api.example.com/openapi.json --http-port 3000

OpenAPI Specification Structure

MockForge supports OpenAPI 3.0+ specifications with the following key components:

  • Paths: API endpoint definitions
  • Methods: HTTP verbs (GET, POST, PUT, DELETE, PATCH)
  • Parameters: Path, query, and header parameters
  • Request Bodies: JSON/XML payload schemas
  • Responses: Status codes and response schemas
  • Components: Reusable schemas and examples

Example OpenAPI Specification

openapi: 3.0.3
info:
  title: User Management API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
    post:
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserInput'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

  /users/{id}:
    get:
      summary: Get user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: User not found

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        email:
          type: string
          format: email
        createdAt:
          type: string
          format: date-time
    UserInput:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string

Dynamic Response Generation

MockForge generates realistic responses automatically based on your OpenAPI schemas, with support for dynamic data through templates.

Automatic Response Generation

For basic use cases, MockForge can generate responses directly from your OpenAPI schemas:

# Start server with automatic response generation
mockforge serve --spec api-spec.json --http-port 3000

This generates:

  • UUIDs for ID fields
  • Random data for string/number fields
  • Current timestamps for date-time fields
  • Valid email addresses for email fields

Template-Enhanced Responses

For more control, use MockForge’s template system in your OpenAPI examples:

paths:
  /users:
    get:
      responses:
        '200':
          description: List of users
          content:
            application/json:
              example:
                users:
                  - id: "{{uuid}}"
                    name: "John Doe"
                    email: "[email protected]"
                    createdAt: "{{now}}"
                    lastLogin: "{{now-1d}}"
                  - id: "{{uuid}}"
                    name: "Jane Smith"
                    email: "[email protected]"
                    createdAt: "{{now-7d}}"
                    lastLogin: "{{now-2h}}"

Template Functions

Data Generation Templates

  • {{uuid}} - Generate unique UUID
  • {{now}} - Current timestamp
  • {{now+1h}} - Future timestamp
  • {{now-1d}} - Past timestamp
  • {{randInt 1 100}} - Random integer
  • {{randFloat 0.0 1.0}} - Random float

Request Data Templates

  • {{request.path.id}} - Access path parameters
  • {{request.query.limit}} - Access query parameters
  • {{request.header.Authorization}} - Access headers
  • {{request.body.name}} - Access request body fields

Request Matching and Routing

MockForge uses sophisticated matching to route requests to appropriate responses.

Matching Priority

  1. Exact Path + Method Match
  2. Parameterized Path Match (e.g., /users/{id})
  3. Query Parameter Conditions
  4. Header-Based Conditions
  5. Request Body Matching
  6. Default Response (catch-all)

Path Parameter Handling

/users/{id}:
  get:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
    responses:
      '200':
        content:
          application/json:
            example:
              id: "{{request.path.id}}"
              name: "User {{request.path.id}}"
              retrievedAt: "{{now}}"

Query Parameter Filtering

/users:
  get:
    parameters:
      - name: status
        in: query
        schema:
          type: string
          enum: [active, inactive]
      - name: limit
        in: query
        schema:
          type: integer
          default: 10
    responses:
      '200':
        content:
          application/json:
            example: "{{#if (eq request.query.status 'active')}}active_users{{else}}all_users{{/if}}"

Response Scenarios

MockForge supports multiple response scenarios for testing different conditions.

Success Responses

responses:
  '200':
    description: Success
    content:
      application/json:
        example:
          status: "success"
          data: { ... }

Error Responses

responses:
  '400':
    description: Bad Request
    content:
      application/json:
        example:
          error: "INVALID_INPUT"
          message: "The provided input is invalid"
  '404':
    description: Not Found
    content:
      application/json:
        example:
          error: "NOT_FOUND"
          message: "Resource not found"
  '500':
    description: Internal Server Error
    content:
      application/json:
        example:
          error: "INTERNAL_ERROR"
          message: "An unexpected error occurred"

Conditional Responses

Use templates to return different responses based on request data:

responses:
  '200':
    content:
      application/json:
        example: |
          {{#if (eq request.query.format 'detailed')}}
          {
            "id": "{{uuid}}",
            "name": "Detailed User",
            "email": "[email protected]",
            "profile": {
              "bio": "Detailed user profile",
              "preferences": { ... }
            }
          }
          {{else}}
          {
            "id": "{{uuid}}",
            "name": "Basic User",
            "email": "[email protected]"
          }
          {{/if}}

Advanced Features

Response Latency Simulation

# Add random latency via the chaos engine
mockforge serve --spec api-spec.json \
  --chaos --chaos-latency-range "100-500"

For full control (jitter, probability, fixed delay, per-route), use observability.chaos.latency.* in YAML. See Chaos Engineering.

Failure Injection

# 10% of requests get 500/503
mockforge serve --spec api-spec.json \
  --chaos --chaos-http-errors "500,503" --chaos-http-error-probability 0.1

Request/Response Recording & Replay

Recording, replay, and proxy modes are configured via CLI flags or YAML — see mockforge serve --help for --record, --replay, --proxy-target.

Testing Your Mocks

Manual Testing with curl

# Test GET endpoint
curl http://localhost:3000/users

# Test POST endpoint
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Test User", "email": "[email protected]"}'

# Test path parameters
curl http://localhost:3000/users/123

# Test query parameters
curl "http://localhost:3000/users?limit=5&status=active"

# Test error scenarios
curl http://localhost:3000/users/999  # Should return 404

Automated Testing

#!/bin/bash
# test-api.sh

BASE_URL="http://localhost:3000"

echo "Testing User API..."

# Test user creation
USER_RESPONSE=$(curl -s -X POST $BASE_URL/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Test User", "email": "[email protected]"}')

echo "Created user: $USER_RESPONSE"

# Extract user ID (assuming response contains id)
USER_ID=$(echo $USER_RESPONSE | jq -r '.id')

# Test user retrieval
RETRIEVED_USER=$(curl -s $BASE_URL/users/$USER_ID)
echo "Retrieved user: $RETRIEVED_USER"

# Test user listing
USER_LIST=$(curl -s $BASE_URL/users)
echo "User list: $USER_LIST"

echo "API tests completed!"

Best Practices

OpenAPI Specification Tips

  1. Use descriptive operation IDs for better organization
  2. Include examples in your OpenAPI spec for consistent responses
  3. Define reusable components for common schemas
  4. Use appropriate HTTP status codes for different scenarios
  5. Document all parameters clearly

Template Usage Guidelines

  1. Enable templates only when needed for security
  2. Use meaningful template variables for maintainability
  3. Test template expansion thoroughly
  4. Avoid complex logic in templates - keep it simple

Response Design Principles

  1. Match real API behavior as closely as possible
  2. Include appropriate error responses for testing
  3. Use consistent data formats across endpoints
  4. Consider pagination for list endpoints
  5. Include metadata like timestamps and request IDs

Performance Considerations

  1. Use static responses when dynamic data isn’t needed
  2. Limit template complexity to maintain response times
  3. Configure appropriate timeouts for your use case
  4. Monitor memory usage with large response payloads

Troubleshooting

Common Issues

Templates not expanding: ensure MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true is set in your environment (it’s off by default to keep responses literal)

OpenAPI spec not loading: Check file path and JSON/YAML syntax

Wrong response returned: Verify request matching rules and parameter handling

Performance issues: Reduce template complexity or use static responses

Port conflicts: Change default ports with --http-port option

Advanced Behavior and Simulation

MockForge supports advanced behavior simulation features for realistic API testing:

Record & Playback

Automatically record API interactions and convert them to replayable fixtures:

# Record the requests the server handles
mockforge serve --spec api-spec.json --recorder --recorder-db ./mockforge-recordings.db

# Convert recordings to stub mappings
mockforge recorder convert --input ./mockforge-recordings.db --output fixtures/

Stateful Behavior

Simulate stateful APIs where responses change based on previous requests:

core:
  stateful:
    enabled: true
    state_machines:
      - name: "order_workflow"
        resource_id_extract:
          type: "path_param"
          param: "order_id"
        transitions:
          - method: "POST"
            path_pattern: "/api/orders"
            from_state: "initial"
            to_state: "pending"

Per-Route Fault Injection

Configure fault injection on specific routes:

core:
  routes:
    - path: "/api/payments/process"
      method: "POST"
      fault_injection:
        enabled: true
        probability: 0.05
        fault_types:
          - type: "http_error"
            status_code: 503

Per-Route Latency

Simulate network conditions per route:

core:
  routes:
    - path: "/api/search"
      method: "GET"
      latency:
        enabled: true
        distribution: "normal"
        mean_ms: 500.0
        std_dev_ms: 100.0

Conditional Proxying

Proxy requests conditionally based on request attributes:

core:
  proxy:
    rules:
      - pattern: "/api/admin/*"
        upstream_url: "https://admin-api.example.com"
        condition: "$.user.role == 'admin'"

For detailed documentation on these features, see Advanced Behavior and Simulation.

For more advanced HTTP mocking features, see the following guides:

OpenAPI Integration

MockForge provides advanced OpenAPI integration capabilities beyond basic spec loading and response generation. This guide covers sophisticated features for enterprise-grade API mocking.

Advanced Request Validation

MockForge supports comprehensive request validation against OpenAPI schemas with multiple validation modes and granular control.

Validation Modes

# Disable validation completely
MOCKFORGE_REQUEST_VALIDATION=off mockforge serve --spec api-spec.json

# Log warnings but allow invalid requests
MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api-spec.json

# Reject invalid requests (default)
MOCKFORGE_REQUEST_VALIDATION=enforce mockforge serve --spec api-spec.json

Response Validation

Enable validation of generated responses against OpenAPI schemas:

# Validate responses against schemas
MOCKFORGE_RESPONSE_VALIDATION=true mockforge serve --spec api-spec.json

Custom Validation Status Codes

Configure HTTP status codes for validation failures:

# Use 422 Unprocessable Entity for validation errors
MOCKFORGE_VALIDATION_STATUS=422 mockforge serve --spec api-spec.json

Validation Overrides

Skip validation for specific routes:

validation:
  mode: enforce
  overrides:
    "GET /health": "off"
    "POST /webhooks/*": "warn"

Aggregated Error Reporting

Control how validation errors are reported:

# Report all validation errors at once
MOCKFORGE_AGGREGATE_ERRORS=true mockforge serve --spec api-spec.json

# Stop at first validation error
MOCKFORGE_AGGREGATE_ERRORS=false mockforge serve --spec api-spec.json

Security Scheme Validation

MockForge validates authentication and authorization requirements defined in your OpenAPI spec.

Supported Security Schemes

  • HTTP Basic Authentication: Validates Authorization: Basic <credentials> headers
  • Bearer Tokens: Validates Authorization: Bearer <token> headers
  • API Keys: Supports header and query parameter API keys
  • OAuth2: Basic OAuth2 flow validation

Security Validation Example

openapi: 3.0.0
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

security:
  - bearerAuth: []
  - apiKey: []

paths:
  /protected:
    get:
      security:
        - bearerAuth: []
# Test with valid Bearer token
curl -H "Authorization: Bearer eyJ0eXAi..." http://localhost:3000/protected

# Test with API key
curl -H "X-API-Key: your-api-key" http://localhost:3000/protected

Schema Resolution and References

MockForge fully supports OpenAPI schema references ($ref) for reusable components.

Component References

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        profile:
          $ref: '#/components/schemas/UserProfile'

    UserProfile:
      type: object
      properties:
        bio:
          type: string
        avatar:
          type: string
          format: uri

  responses:
    UserResponse:
      description: User data
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/User'

paths:
  /users/{id}:
    get:
      responses:
        '200':
          $ref: '#/components/responses/UserResponse'

Request Body References

components:
  requestBodies:
    UserCreate:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - name
              - email
            properties:
              name:
                type: string
              email:
                type: string
                format: email

paths:
  /users:
    post:
      requestBody:
        $ref: '#/components/requestBodies/UserCreate'

Multiple OpenAPI Specifications

MockForge can serve multiple OpenAPI specifications simultaneously with path-based routing.

Configuration for Multiple Specs

server:
  http_port: 3000

specs:
  - name: user-api
    path: /api/v1
    spec: user-api.json
  - name: admin-api
    path: /api/admin
    spec: admin-api.json

Base Path Routing

# Routes to user-api.json endpoints
curl http://localhost:3000/api/v1/users

# Routes to admin-api.json endpoints
curl http://localhost:3000/api/admin/users

Advanced Routing and Matching

MockForge provides sophisticated request matching beyond simple path/method combinations.

Path Parameter Constraints

paths:
  /users/{id}:
    get:
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            pattern: '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'

Query Parameter Matching

paths:
  /users:
    get:
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [active, inactive, pending]
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 10

Header-Based Routing

paths:
  /api/v1/users:
    get:
      parameters:
        - name: X-API-Version
          in: header
          schema:
            type: string
            enum: [v1, v2]

Template Expansion in Responses

Advanced template features for dynamic response generation.

Advanced Template Functions

responses:
  '200':
    content:
      application/json:
        example:
          id: "{{uuid}}"
          createdAt: "{{now}}"
          expiresAt: "{{now+1h}}"
          lastModified: "{{now-30m}}"
          randomValue: "{{randInt 1 100}}"
          randomFloat: "{{randFloat 0.0 5.0}}"
          userAgent: "{{request.header.User-Agent}}"
          apiVersion: "{{request.header.X-API-Version}}"
          userId: "{{request.path.id}}"
          searchQuery: "{{request.query.q}}"

Conditional Templates

responses:
  '200':
    content:
      application/json:
        example: |
          {{#if (eq request.query.format 'detailed')}}
          {
            "id": "{{uuid}}",
            "name": "Detailed User",
            "profile": {
              "bio": "User biography",
              "preferences": {}
            }
          }
          {{else}}
          {
            "id": "{{uuid}}",
            "name": "Basic User"
          }
          {{/if}}

Template Security

Enable template expansion only when needed:

# Enable template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.json

Performance Optimization

Strategies for handling large OpenAPI specifications efficiently.

Lazy Loading

MockForge loads and parses OpenAPI specs on startup but generates routes lazily:

# Monitor startup performance
time mockforge serve --spec large-api.json

Route Caching

Generated routes are cached in memory for optimal performance:

# Check memory usage with large specs
MOCKFORGE_LOG_LEVEL=debug mockforge serve --spec large-api.json

Validation Performance

Disable expensive validations in high-throughput scenarios:

# Disable response validation for better performance
MOCKFORGE_RESPONSE_VALIDATION=false mockforge serve --spec api-spec.json

Custom Validation Options

Fine-tune validation behavior for your specific needs.

Validation Configuration

validation:
  mode: enforce
  aggregate_errors: true
  validate_responses: false
  status_code: 422
  overrides:
    "GET /health": "off"
    "POST /webhooks/*": "warn"
  admin_skip_prefixes:
    - "/admin"
    - "/internal"

Environment Variables

# Validation mode
MOCKFORGE_REQUEST_VALIDATION=enforce

# Error aggregation
MOCKFORGE_AGGREGATE_ERRORS=true

# Response validation
MOCKFORGE_RESPONSE_VALIDATION=false

# Custom status code
MOCKFORGE_VALIDATION_STATUS=422

# Template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

OpenAPI Extensions

MockForge supports OpenAPI extensions (x- prefixed properties) for custom behavior.

Custom Extensions

paths:
  /users:
    get:
      x-mockforge-delay: 1000  # Add 1 second delay
      x-mockforge-failure-rate: 0.1  # 10% failure rate
      responses:
        '200':
          x-mockforge-template: true  # Enable template expansion

Vendor Extensions

info:
  x-mockforge-config:
    enable_cors: true
    default_response_format: json

paths:
  /api/users:
    x-vendor-custom-behavior: enabled

Troubleshooting

Common issues and solutions for advanced OpenAPI integration.

Validation Errors

Problem: Requests are rejected with validation errors

{
  "error": "request validation failed",
  "status": 422,
  "details": [
    {
      "path": "body.name",
      "code": "required",
      "message": "Missing required field: name"
    }
  ]
}

Solutions:

# Switch to warning mode
MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api-spec.json

# Disable validation for specific routes
# Add to config.yaml:
validation:
  overrides:
    "POST /users": "off"

Schema Reference Issues

Problem: $ref references not resolving correctly

Solutions:

  • Ensure component names match exactly
  • Check that referenced components exist
  • Validate your OpenAPI spec with external tools

Performance Issues

Problem: Slow startup or high memory usage with large specs

Solutions:

# Disable non-essential features
MOCKFORGE_RESPONSE_VALIDATION=false
MOCKFORGE_AGGREGATE_ERRORS=false

# Monitor with debug logging
MOCKFORGE_LOG_LEVEL=debug mockforge serve --spec api-spec.json

Security Validation Failures

Problem: Authentication requests failing

Solutions:

  • Verify security scheme definitions
  • Check header formats (e.g., Bearer prefix)
  • Ensure global security requirements are met

Template Expansion Issues

Problem: Templates not expanding in responses

Solutions:

# Enable template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.json

# Check template syntax
# Use {{variable}} format, not ${variable}

Best Practices

Specification Management

  1. Version Control: Keep OpenAPI specs in version control alongside mock configurations
  2. Validation: Use external validators to ensure spec correctness
  3. Documentation: Include comprehensive examples and descriptions
  4. Modularity: Use components and references for maintainable specs

Performance Tuning

  1. Selective Validation: Disable validation for high-traffic endpoints
  2. Template Usage: Only enable templates when dynamic data is needed
  3. Caching: Leverage MockForge’s built-in route caching
  4. Monitoring: Monitor memory usage and response times

Security Considerations

  1. Validation Modes: Use appropriate validation levels for different environments
  2. Template Security: Be cautious with user-controlled template input
  3. Authentication: Properly configure security schemes for protected endpoints
  4. Overrides: Use validation overrides judiciously

For basic OpenAPI integration features, see the HTTP Mocking guide. For dynamic data generation, see the Dynamic Data guide.

Custom Responses

MockForge provides multiple powerful ways to create custom HTTP responses beyond basic OpenAPI schema generation. This guide covers advanced response customization techniques including plugins, overrides, and dynamic generation.

Response Override Rules

Override rules patch the responses MockForge generates from your OpenAPI spec, without editing the spec. Each rule picks operations with targets, then applies JSON patch operations to the response body.

Where rules come from

Rules are combined in this order, and all of them can be replaced at runtime:

  1. The overrides: list in mockforge.yaml.
  2. YAML files named by MOCKFORGE_HTTP_OVERRIDES_GLOB (comma-separated globs or absolute paths). Each file is a list of rules.
  3. A JSON array of rules in MOCKFORGE_HTTP_OVERRIDES. Hosted mocks receive their rules this way.
# mockforge.yaml
overrides:
  - name: Stamp a request id
    targets: ["operation:getUser"]
    patch:
      - op: add
        path: /requestId
        value: "{{uuid}}"
    post_templating: true

  - name: Fail payments
    targets: ["tag:Payments"]
    patch:
      - op: replace
        path: /status
        value: FAILED

Targets

A rule applies when any of its targets matches the operation.

TargetMatches
operation:getUserThe operation whose operationId is getUser
tag:UsersOperations tagged Users in the spec
path:^/users/Path templates matching the regex, such as /users/{id}
regex:^listOperation IDs matching the regex
*Every operation

Patch operations

path is a JSON pointer into the response body. Use "" for the whole body.

patch:
  - op: add          # add or set a field
    path: /metadata/source
    value: mock
  - op: replace      # replace an existing value
    path: /user/tier
    value: gold
  - op: remove       # delete a field
    path: /debug

With mode: merge, add and replace deep-merge objects into the existing value instead of overwriting it. The default is mode: replace.

Conditions

when limits a rule to matching requests. Supported forms:

ConditionTrue when
header[x-scenario]=emptyThe request header equals the value (names are case-insensitive)
header[x-scenario]!=emptyThe header differs from the value
query[format]=detailedThe query parameter equals the value
$.request.body.plan == 'pro'A JSONPath into the request body compares equal
AND(a, b), OR(a, b), NOT(a)Combinations of the above
overrides:
  - name: Empty list for demos
    targets: ["path:^/users$"]
    when: "header[x-scenario]=empty"
    patch:
      - op: replace
        path: ""
        value: []

Templating

Token values such as {{uuid}} in rule files are expanded once, when the file loads. Set post_templating: true to expand tokens in the patched body on every response instead.

Turning rules off

Set enabled: false to keep a rule without applying it. The admin UI’s Overrides page toggles this for you.

Changing rules at runtime

With --admin, the admin server exposes the live rule set:

# Read the rules
curl http://localhost:9080/__mockforge/overrides

# Replace them all; the next response uses the new rules
curl -X PUT http://localhost:9080/__mockforge/overrides \
  -H 'content-type: application/json' \
  -d '{"rules": [{"targets": ["operation:ping"], "patch": [{"op": "add", "path": "/overridden", "value": true}]}]}'

A PUT is validated as a whole. An invalid target regex or JSON pointer returns 400 with the reason, and the previous rules stay in place. Runtime changes are not written back to mockforge.yaml.

Response Plugins

Create custom response generation logic using MockForge’s plugin system.

Response Generator Plugin

Implement the ResponsePlugin trait for complete response control:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::*;

pub struct CustomResponsePlugin;

#[async_trait::async_trait]
impl ResponsePlugin for CustomResponsePlugin {
    fn capabilities(&self) -> PluginCapabilities {
        PluginCapabilities {
            network: NetworkCapabilities {
                allow_http_outbound: true,
                allowed_hosts: vec!["api.example.com".to_string()],
            },
            filesystem: FilesystemCapabilities::default(),
            resources: PluginResources {
                max_memory_bytes: 50 * 1024 * 1024,
                max_cpu_time_ms: 5000,
            },
            custom: HashMap::new(),
        }
    }

    async fn initialize(&self, config: &ResponsePluginConfig) -> Result<()> {
        // Plugin initialization
        Ok(())
    }

    async fn can_handle(
        &self,
        _context: &PluginContext,
        request: &ResponseRequest,
        _config: &ResponsePluginConfig,
    ) -> Result<PluginResult<bool>> {
        // Check if this plugin should handle the request
        let should_handle = request.path.starts_with("/api/custom/");
        Ok(PluginResult::success(should_handle, 0))
    }

    async fn generate_response(
        &self,
        _context: &PluginContext,
        request: &ResponseRequest,
        _config: &ResponsePluginConfig,
    ) -> Result<PluginResult<ResponseData>> {
        // Generate custom response
        match request.path.as_str() {
            "/api/custom/weather" => {
                let weather_data = serde_json::json!({
                    "temperature": 22,
                    "condition": "sunny",
                    "location": request.query_param("location").unwrap_or("Unknown")
                });
                Ok(PluginResult::success(
                    ResponseData::json(200, &weather_data)?,
                    0
                ))
            }
            "/api/custom/time" => {
                let time_data = serde_json::json!({
                    "current_time": chrono::Utc::now().to_rfc3339(),
                    "timezone": request.query_param("tz").unwrap_or("UTC")
                });
                Ok(PluginResult::success(
                    ResponseData::json(200, &time_data)?,
                    0
                ))
            }
            _ => Ok(PluginResult::success(
                ResponseData::not_found("Custom endpoint not found"),
                0
            ))
        }
    }

    fn priority(&self) -> i32 { 100 }

    fn validate_config(&self, _config: &ResponsePluginConfig) -> Result<()> {
        Ok(())
    }

    fn supported_content_types(&self) -> Vec<String> {
        vec!["application/json".to_string()]
    }
}
}

Plugin Configuration

Configure response plugins in your MockForge setup:

# plugin.yaml
name: custom-response-plugin
version: "1.0.0"
type: response

config:
  enabled: true
  priority: 100
  content_types:
    - "application/json"
  url_patterns:
    - "/api/custom/*"
  methods:
    - "GET"
    - "POST"
  settings:
    external_api_timeout: 5000
    cache_enabled: true

Response Modifier Plugin

Modify responses after generation using the ResponseModifierPlugin trait:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::*;

pub struct ResponseModifierPlugin;

#[async_trait::async_trait]
impl ResponseModifierPlugin for ResponseModifierPlugin {
    fn capabilities(&self) -> PluginCapabilities {
        PluginCapabilities::default()
    }

    async fn initialize(&self, _config: &ResponseModifierConfig) -> Result<()> {
        Ok(())
    }

    async fn should_modify(
        &self,
        _context: &PluginContext,
        _request: &ResponseRequest,
        response: &ResponseData,
        _config: &ResponseModifierConfig,
    ) -> Result<PluginResult<bool>> {
        // Modify successful JSON responses
        let should_modify = response.status_code == 200 &&
                           response.content_type == "application/json";
        Ok(PluginResult::success(should_modify, 0))
    }

    async fn modify_response(
        &self,
        _context: &PluginContext,
        _request: &ResponseRequest,
        mut response: ResponseData,
        _config: &ResponseModifierConfig,
    ) -> Result<PluginResult<ResponseData>> {
        // Add custom headers
        response.headers.insert(
            "X-Custom-Header".to_string(),
            "Modified by plugin".to_string()
        );

        // Add metadata to JSON responses
        if let Some(json_str) = response.body_as_string() {
            if let Ok(mut json_value) = serde_json::from_str::<serde_json::Value>(&json_str) {
                if let Some(obj) = json_value.as_object_mut() {
                    obj.insert("_metadata".to_string(), serde_json::json!({
                        "modified_by": "ResponseModifierPlugin",
                        "timestamp": chrono::Utc::now().timestamp()
                    }));
                }

                let modified_body = serde_json::to_vec(&json_value)
                    .map_err(|e| PluginError::execution(format!("JSON serialization error: {}", e)))?;
                response.body = modified_body;
            }
        }

        Ok(PluginResult::success(response, 0))
    }

    fn priority(&self) -> i32 { 50 }

    fn validate_config(&self, _config: &ResponseModifierConfig) -> Result<()> {
        Ok(())
    }
}
}

Template Plugins

Extend MockForge’s templating system with custom functions.

Custom Template Functions

#![allow(unused)]
fn main() {
use mockforge_plugin_core::*;

pub struct BusinessTemplatePlugin;

impl TemplatePlugin for BusinessTemplatePlugin {
    fn execute_function(
        &mut self,
        function_name: &str,
        args: &[TemplateArg],
        _context: &PluginContext,
    ) -> PluginResult<String> {
        match function_name {
            "business_id" => {
                // Generate business-specific ID
                let id = format!("BIZ-{:010}", rand::random::<u32>());
                PluginResult::success(id, 0)
            }
            "department_name" => {
                // Generate department name
                let departments = ["Engineering", "Sales", "Marketing", "HR", "Finance"];
                let dept = departments[rand::random::<usize>() % departments.len()];
                PluginResult::success(dept.to_string(), 0)
            }
            "employee_data" => {
                // Generate complete employee object
                let employee = serde_json::json!({
                    "id": format!("EMP-{:06}", rand::random::<u32>() % 1000000),
                    "name": "{{faker.name}}",
                    "department": "{{department_name}}",
                    "salary": rand::random::<u32>() % 50000 + 50000,
                    "hire_date": "{{faker.date.past 365}}"
                });
                PluginResult::success(employee.to_string(), 0)
            }
            _ => PluginResult::failure(
                format!("Unknown function: {}", function_name),
                0
            )
        }
    }

    fn get_available_functions(&self) -> Vec<TemplateFunction> {
        vec![
            TemplateFunction {
                name: "business_id".to_string(),
                description: "Generate a business ID".to_string(),
                args: vec![],
                return_type: "string".to_string(),
            },
            TemplateFunction {
                name: "department_name".to_string(),
                description: "Generate a department name".to_string(),
                args: vec![],
                return_type: "string".to_string(),
            },
            TemplateFunction {
                name: "employee_data".to_string(),
                description: "Generate complete employee data".to_string(),
                args: vec![],
                return_type: "json".to_string(),
            },
        ]
    }

    fn get_capabilities(&self) -> PluginCapabilities {
        PluginCapabilities::default()
    }

    fn health_check(&self) -> PluginHealth {
        PluginHealth::healthy("Template plugin healthy".to_string(), PluginMetrics::default())
    }
}
}

Using Custom Templates

# OpenAPI spec with custom templates
paths:
  /employees:
    get:
      responses:
        '200':
          content:
            application/json:
              example:
                employees:
                  - "{{employee_data}}"
                  - "{{employee_data}}"
                business_id: "{{business_id}}"

Configuration-Based Custom Responses

Define custom responses directly in configuration files.

Route-Specific Responses

# mockforge.yaml
http:
  port: 3000
  routes:
    - path: /api/custom/dashboard
      method: GET
      response:
        status: 200
        headers:
          Content-Type: application/json
          X-Custom-Header: Dashboard-Data
        body: |
          {
            "widgets": [
              {
                "id": "sales-chart",
                "type": "chart",
                "data": [120, 150, 180, 200, 250]
              },
              {
                "id": "user-stats",
                "type": "stats",
                "data": {
                  "total_users": 15420,
                  "active_users": 8920,
                  "new_signups": 245
                }
              }
            ],
            "last_updated": "{{now}}"
          }

    - path: /api/custom/report
      method: POST
      response:
        status: 201
        headers:
          Location: /api/reports/123
        body: |
          {
            "report_id": "RPT-{{randInt 1000 9999}}",
            "status": "processing",
            "estimated_completion": "{{now+5m}}"
          }

Dynamic Route Matching

routes:
  # Path parameters
  - path: /api/users/{userId}/profile
    method: GET
    response:
      status: 200
      body: |
        {
          "user_id": "{{request.path.userId}}",
          "name": "{{faker.name}}",
          "email": "{{faker.email}}",
          "profile": {
            "bio": "{{faker.sentence}}",
            "location": "{{faker.city}}, {{faker.country}}"
          }
        }

  # Query parameter conditions
  - path: /api/search
    method: GET
    response:
      status: 200
      body: |
        {{#if (eq request.query.type 'users')}}
        {
          "results": [
            {"id": 1, "name": "John", "type": "user"},
            {"id": 2, "name": "Jane", "type": "user"}
          ]
        }
        {{else if (eq request.query.type 'posts')}}
        {
          "results": [
            {"id": 1, "title": "Post 1", "type": "post"},
            {"id": 2, "title": "Post 2", "type": "post"}
          ]
        }
        {{else}}
        {
          "results": [],
          "message": "No results found for type: {{request.query.type}}"
        }
        {{/if}}

Error Response Customization

Create sophisticated error responses for different scenarios.

Structured Error Responses

routes:
  - path: /api/users/{userId}
    method: GET
    response:
      status: 404
      headers:
        Content-Type: application/json
      body: |
        {
          "error": {
            "code": "USER_NOT_FOUND",
            "message": "User with ID {{request.path.userId}} not found",
            "details": {
              "user_id": "{{request.path.userId}}",
              "requested_at": "{{now}}",
              "request_id": "{{uuid}}"
            },
            "suggestions": [
              "Check if the user ID is correct",
              "Verify the user exists in the system",
              "Try searching by email instead"
            ]
          }
        }

  - path: /api/orders
    method: POST
    response:
      status: 422
      body: |
        {
          "error": {
            "code": "VALIDATION_ERROR",
            "message": "Request validation failed",
            "validation_errors": [
              {
                "field": "customer_email",
                "code": "invalid_format",
                "message": "Email format is invalid"
              },
              {
                "field": "order_items",
                "code": "min_items",
                "message": "At least one order item is required"
              }
            ]
          }
        }

Conditional Error Responses

routes:
  - path: /api/payments
    method: POST
    response:
      status: 402
      condition: "request.header.X-Test-Mode == 'insufficient_funds'"
      body: |
        {
          "error": "INSUFFICIENT_FUNDS",
          "message": "Payment failed due to insufficient funds",
          "details": {
            "available_balance": 50.00,
            "requested_amount": 100.00,
            "currency": "USD"
          }
        }

  - path: /api/payments
    method: POST
    response:
      status: 500
      condition: "request.header.X-Test-Mode == 'server_error'"
      body: |
        {
          "error": "INTERNAL_SERVER_ERROR",
          "message": "An unexpected error occurred while processing payment",
          "reference_id": "ERR-{{randInt 100000 999999}}",
          "timestamp": "{{now}}"
        }

Advanced Response Features

Response Delays and Latency

routes:
  - path: /api/slow-endpoint
    method: GET
    response:
      status: 200
      delay_ms: 2000  # 2 second delay
      body: |
        {
          "message": "This response was delayed",
          "timestamp": "{{now}}"
        }

  - path: /api/variable-delay
    method: GET
    response:
      status: 200
      delay_ms: "{{randInt 100 5000}}"  # Random delay between 100ms-5s
      body: |
        {
          "message": "Random delay applied",
          "delay_applied_ms": "{{_delay_ms}}"
        }

Response Caching

routes:
  - path: /api/cached-data
    method: GET
    response:
      status: 200
      headers:
        Cache-Control: max-age=300
        X-Cache-Status: "{{_cache_hit ? 'HIT' : 'MISS'}}"
      cache: true
      cache_ttl_seconds: 300
      body: |
        {
          "data": "This response may be cached",
          "generated_at": "{{now}}",
          "cache_expires_at": "{{now+5m}}"
        }

Binary Response Handling

routes:
  - path: /api/download/{filename}
    method: GET
    response:
      status: 200
      headers:
        Content-Type: application/octet-stream
        Content-Disposition: attachment; filename="{{request.path.filename}}"
      body_file: "/path/to/binary/files/{{request.path.filename}}"

  - path: /api/images/{imageId}
    method: GET
    response:
      status: 200
      headers:
        Content-Type: image/png
        Cache-Control: max-age=3600
      body_base64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="

Testing Custom Responses

Manual Testing

# Test custom route
curl http://localhost:3000/api/custom/dashboard

# Test with parameters
curl "http://localhost:3000/api/users/123/profile"

# Test error conditions
curl -H "X-Test-Mode: insufficient_funds" \
     http://localhost:3000/api/payments \
     -X POST \
     -d '{}'

Automated Testing

#!/bin/bash
# test-custom-responses.sh

BASE_URL="http://localhost:3000"

echo "Testing custom responses..."

# Test dashboard endpoint
DASHBOARD_RESPONSE=$(curl -s $BASE_URL/api/custom/dashboard)
echo "Dashboard response:"
echo $DASHBOARD_RESPONSE | jq '.'

# Test user profile with path parameter
USER_RESPONSE=$(curl -s $BASE_URL/api/users/456/profile)
echo "User profile response:"
echo $USER_RESPONSE | jq '.'

# Test error responses
ERROR_RESPONSE=$(curl -s -H "X-Test-Mode: insufficient_funds" \
                      -X POST \
                      -d '{}' \
                      $BASE_URL/api/payments)
echo "Error response:"
echo $ERROR_RESPONSE | jq '.'

echo "Custom response tests completed!"

Best Practices

Plugin Development

  1. Resource Limits: Set appropriate memory and CPU limits for plugins
  2. Error Handling: Implement proper error handling and logging
  3. Testing: Thoroughly test plugins with various inputs
  4. Documentation: Document plugin capabilities and configuration options

Override Usage

  1. Selective Application: Use specific targets to avoid unintended modifications
  2. Version Control: Keep override configurations in version control
  3. Testing: Test overrides with different request scenarios
  4. Performance: Minimize complex conditions and patch operations

Response Design

  1. Consistency: Maintain consistent response formats across endpoints
  2. Error Details: Provide meaningful error messages and codes
  3. Metadata: Include relevant metadata like timestamps and request IDs
  4. Content Types: Set appropriate Content-Type headers

Security Considerations

  1. Input Validation: Validate all inputs in custom plugins
  2. Resource Limits: Prevent resource exhaustion attacks
  3. Authentication: Implement proper authentication for sensitive endpoints
  4. Logging: Log security-relevant events without exposing sensitive data

Troubleshooting

Plugin Issues

Plugin not loading: Check plugin configuration and file paths Plugin timeout: Increase resource limits or optimize plugin code Plugin errors: Check plugin logs and error messages

Override Problems

Overrides not applying: Verify target selectors and patch syntax JSON patch errors: Validate patch operations against JSON structure Condition evaluation: Test conditional expressions with sample requests

Performance Issues

Slow responses: Profile plugin execution and optimize bottlenecks Memory usage: Monitor plugin memory consumption and adjust limits Template expansion: Simplify complex templates or use static responses

For basic HTTP mocking features, see the HTTP Mocking guide. For advanced templating, see the Dynamic Data guide.

Dynamic Data

MockForge provides powerful dynamic data generation capabilities through its templating system and faker integration. This guide covers generating realistic, varied responses for comprehensive API testing and development.

Template Expansion Basics

MockForge uses a lightweight templating system with {{token}} syntax to inject dynamic values into responses.

Enabling Templates

Templates are disabled by default for security. Enable them using:

# Environment variable
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.json

# Configuration file
http:
  response_template_expand: true

Basic Template Syntax

paths:
  /users:
    get:
      responses:
        '200':
          content:
            application/json:
              example:
                users:
                  - id: "{{uuid}}"
                    name: "{{faker.name}}"
                    email: "{{faker.email}}"
                    created_at: "{{now}}"

Time-Based Templates

Generate timestamps and time offsets for realistic temporal data.

Current Time

responses:
  '200':
    content:
      application/json:
        example:
          current_time: "{{now}}"
          server_timestamp: "{{now}}"

Time Offsets

responses:
  '200':
    content:
      application/json:
        example:
          created_at: "{{now-7d}}"
          expires_at: "{{now+1h}}"
          last_login: "{{now-30m}}"
          scheduled_for: "{{now+2h}}"

Supported units:

  • s - seconds
  • m - minutes
  • h - hours
  • d - days

Random Data Generation

Generate random values for varied test data.

Random Integers

responses:
  '200':
    content:
      application/json:
        example:
          user_count: "{{randInt 1 100}}"
          age: "{{randInt 18 80}}"
          score: "{{randInt -10 10}}"

Random Floats

responses:
  '200':
    content:
      application/json:
        example:
          price: "{{randFloat 9.99 999.99}}"
          rating: "{{randFloat 1.0 5.0}}"
          percentage: "{{randFloat 0.0 100.0}}"

UUID Generation

Generate unique identifiers for entities.

responses:
  '200':
    content:
      application/json:
        example:
          id: "{{uuid}}"
          order_id: "{{uuid}}"
          transaction_id: "{{uuid}}"

Faker Data Generation

Generate realistic fake data using the Faker library.

Basic Faker Functions

responses:
  '200':
    content:
      application/json:
        example:
          user:
            id: "{{uuid}}"
            name: "{{faker.name}}"
            email: "{{faker.email}}"
            created_at: "{{now}}"

Extended Faker Functions

When the data-faker feature is enabled, additional functions are available:

responses:
  '200':
    content:
      application/json:
        example:
          user:
            name: "{{faker.name}}"
            email: "{{faker.email}}"
            phone: "{{faker.phone}}"
            address: "{{faker.address}}"
            company: "{{faker.company}}"
          product:
            name: "{{faker.word}}"
            description: "{{faker.sentence}}"
            color: "{{faker.color}}"
            url: "{{faker.url}}"
            ip_address: "{{faker.ip}}"

Disabling Faker

For deterministic testing, disable faker tokens:

MOCKFORGE_FAKE_TOKENS=false mockforge serve --spec api-spec.json

Request Data Access

Access data from incoming requests to create dynamic responses.

Path Parameters

paths:
  /users/{userId}:
    get:
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          content:
            application/json:
              example:
                id: "{{request.path.userId}}"
                name: "User {{request.path.userId}}"
                retrieved_at: "{{now}}"

Query Parameters

paths:
  /users:
    get:
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
        - name: format
          in: query
          schema:
            type: string
            enum: [brief, detailed]
      responses:
        '200':
          content:
            application/json:
              example: |
                {{#if (eq request.query.format 'detailed')}}
                {
                  "users": [
                    {
                      "id": "{{uuid}}",
                      "name": "{{faker.name}}",
                      "email": "{{faker.email}}",
                      "profile": {
                        "bio": "{{faker.sentence}}",
                        "location": "{{faker.address}}"
                      }
                    }
                  ],
                  "limit": {{request.query.limit}},
                  "format": "{{request.query.format}}"
                }
                {{else}}
                {
                  "users": [
                    {
                      "id": "{{uuid}}",
                      "name": "{{faker.name}}",
                      "email": "{{faker.email}}"
                    }
                  ],
                  "limit": {{request.query.limit}}
                }
                {{/if}}

Request Body Access

paths:
  /users:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
      responses:
        '201':
          content:
            application/json:
              example:
                id: "{{uuid}}"
                name: "{{request.body.name}}"
                email: "{{request.body.email}}"
                created_at: "{{now}}"
                welcome_message: "Welcome {{request.body.name}}!"

Headers Access

responses:
  '200':
    content:
      application/json:
        example:
          user_agent: "{{request.header.User-Agent}}"
          api_version: "{{request.header.X-API-Version}}"
          authorization: "{{request.header.Authorization}}"

Conditional Templates

Use Handlebars-style conditionals for complex logic.

Basic Conditionals

responses:
  '200':
    content:
      application/json:
        example: |
          {{#if (eq request.query.format 'detailed')}}
          {
            "data": {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "details": {
                "bio": "{{faker.paragraph}}",
                "stats": {
                  "login_count": {{randInt 1 1000}},
                  "last_active": "{{now-1d}}"
                }
              }
            }
          }
          {{else}}
          {
            "data": {
              "id": "{{uuid}}",
              "name": "{{faker.name}}"
            }
          }
          {{/if}}

Multiple Conditions

responses:
  '200':
    content:
      application/json:
        example: |
          {{#if (eq request.query.type 'admin')}}
          {
            "user": {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "role": "admin",
              "permissions": ["read", "write", "delete", "admin"]
            }
          }
          {{else if (eq request.query.type 'premium')}}
          {
            "user": {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "role": "premium",
              "permissions": ["read", "write"]
            }
          }
          {{else}}
          {
            "user": {
              "id": "{{uuid}}",
              "name": "{{faker.name}}",
              "role": "basic",
              "permissions": ["read"]
            }
          }
          {{/if}}

Data Generation Templates

MockForge includes built-in data generation templates for common entities.

User Template

# Generate user data
mockforge data template user --rows 10 --format json

# Output:
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "name": "John Doe",
    "created_at": "2024-01-15T10:30:00Z",
    "active": true
  }
]

Product Template

# Generate product data
mockforge data template product --rows 5 --format csv

# Output:
id,name,description,price,category,in_stock
550e8400-e29b-41d4-a716-446655440001,Wireless Headphones,High-quality wireless headphones with noise cancellation,199.99,Electronics,true

Order Template

# Generate order data with relationships
mockforge data template order --rows 3 --format json --rag

# Output:
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_amount": 299.97,
    "status": "completed",
    "created_at": "2024-01-16T14:20:00Z"
  }
]

Advanced Templating Features

Encryption Functions

Secure sensitive data in responses:

responses:
  '200':
    content:
      application/json:
        example:
          user:
            id: "{{uuid}}"
            name: "{{encrypt 'user_name' faker.name}}"
            email: "{{encrypt 'user_email' faker.email}}"
            ssn: "{{encrypt 'sensitive' '123-45-6789'}}"

Decryption

Access encrypted data:

# In templates that need to decrypt
decrypted_name: "{{decrypt 'user_name' request.body.encrypted_name}}"

File System Access

Read external files for dynamic content:

responses:
  '200':
    content:
      application/json:
        example:
          config: "{{fs.readFile 'config.json'}}"
          template: "{{fs.readFile 'templates/welcome.html'}}"

Request Chaining Context

Access data from previous requests in chained scenarios.

Chain Variables

# In chained request templates
responses:
  '200':
    content:
      application/json:
        example:
          previous_request_id: "{{chain.request_id}}"
          previous_user_id: "{{chain.user.id}}"
          session_token: "{{chain.auth.token}}"

Custom Template Plugins

Extend templating with custom functions via plugins.

Template Plugin Example

#![allow(unused)]
fn main() {
use mockforge_plugin_core::*;

pub struct BusinessTemplatePlugin;

impl TemplatePlugin for BusinessTemplatePlugin {
    fn execute_function(
        &mut self,
        function_name: &str,
        args: &[TemplateArg],
        _context: &PluginContext,
    ) -> PluginResult<String> {
        match function_name {
            "business_id" => {
                let id = format!("BIZ-{:010}", rand::random::<u32>());
                PluginResult::success(id, 0)
            }
            "department" => {
                let depts = ["Engineering", "Sales", "Marketing", "HR"];
                let dept = depts[rand::random::<usize>() % depts.len()];
                PluginResult::success(dept.to_string(), 0)
            }
            "salary" => {
                let salary = rand::random::<u32>() % 150000 + 50000;
                PluginResult::success(salary.to_string(), 0)
            }
            _ => PluginResult::failure(
                format!("Unknown function: {}", function_name),
                0
            )
        }
    }

    fn get_available_functions(&self) -> Vec<TemplateFunction> {
        vec![
            TemplateFunction {
                name: "business_id".to_string(),
                description: "Generate business ID".to_string(),
                args: vec![],
                return_type: "string".to_string(),
            },
            TemplateFunction {
                name: "department".to_string(),
                description: "Generate department name".to_string(),
                args: vec![],
                return_type: "string".to_string(),
            },
            TemplateFunction {
                name: "salary".to_string(),
                description: "Generate salary amount".to_string(),
                args: vec![],
                return_type: "string".to_string(),
            },
        ]
    }

    fn get_capabilities(&self) -> PluginCapabilities {
        PluginCapabilities::default()
    }

    fn health_check(&self) -> PluginHealth {
        PluginHealth::healthy("Business template plugin healthy".to_string(), PluginMetrics::default())
    }
}
}

Using Custom Templates

responses:
  '200':
    content:
      application/json:
        example:
          employee:
            id: "{{business_id}}"
            name: "{{faker.name}}"
            department: "{{department}}"
            salary: "{{salary}}"
            hire_date: "{{now-1y}}"

Configuration and Security

Template Security Settings

# mockforge.yaml
http:
  response_template_expand: true
  template_security:
    allow_file_access: false
    allow_encryption: true
    max_template_depth: 10
    timeout_ms: 5000

Environment Variables

# Enable template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

# Disable faker for deterministic tests
MOCKFORGE_FAKE_TOKENS=false

# Set validation status for template errors
MOCKFORGE_VALIDATION_STATUS=422

# Control template execution timeout
MOCKFORGE_TEMPLATE_TIMEOUT_MS=5000

Testing with Dynamic Data

Manual Testing

# Test template expansion
curl http://localhost:3000/users

# Test with query parameters
curl "http://localhost:3000/users?format=detailed&limit=5"

# Test path parameters
curl http://localhost:3000/users/123

# Test POST with body access
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Test User", "email": "[email protected]"}'

Automated Testing

#!/bin/bash
# test-dynamic-data.sh

BASE_URL="http://localhost:3000"

echo "Testing dynamic data generation..."

# Test basic templates
USER_RESPONSE=$(curl -s $BASE_URL/users)
echo "User response with templates:"
echo $USER_RESPONSE | jq '.'

# Test conditional templates
DETAILED_RESPONSE=$(curl -s "$BASE_URL/users?format=detailed")
echo "Detailed format response:"
echo $DETAILED_RESPONSE | jq '.'

BASIC_RESPONSE=$(curl -s "$BASE_URL/users?format=basic")
echo "Basic format response:"
echo $BASIC_RESPONSE | jq '.'

# Test faker data
PRODUCT_RESPONSE=$(curl -s $BASE_URL/products)
echo "Product response with faker data:"
echo $PRODUCT_RESPONSE | jq '.'

echo "Dynamic data tests completed!"

Best Practices

Template Usage

  1. Enable Selectively: Only enable template expansion where needed for security
  2. Validate Input: Sanitize request data used in templates
  3. Test Thoroughly: Test template expansion with various inputs
  4. Monitor Performance: Templates add processing overhead

Data Generation

  1. Use Appropriate Faker: Choose faker functions that match your domain
  2. Maintain Consistency: Use consistent data patterns across endpoints
  3. Consider Relationships: Generate related data that makes sense together
  4. Balance Realism: Generate realistic but not sensitive data

Security Considerations

  1. Input Sanitization: Never trust request data in templates
  2. File Access: Disable file system access in production if not needed
  3. Encryption: Use encryption functions for sensitive data
  4. Rate Limiting: Consider rate limiting for expensive template operations

Performance Optimization

  1. Cache Static Parts: Cache template parsing for frequently used templates
  2. Limit Complexity: Avoid deeply nested conditionals and complex logic
  3. Profile Execution: Monitor template execution time and optimize slow functions
  4. Use Appropriate Timeouts: Set reasonable timeouts for template execution

Troubleshooting

Template Not Expanding

Problem: Templates appear as literal text in responses

Solutions:

# Enable template expansion
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.json

# Check configuration
# Ensure response_template_expand: true in config

Faker Functions Not Working

Problem: Faker functions return empty or error values

Solutions:

# Ensure faker is enabled
MOCKFORGE_FAKE_TOKENS=true mockforge serve --spec api-spec.json

# Check if data-faker feature is enabled
# For extended faker functions, ensure the feature is compiled in

Request Data Access Issues

Problem: request.* variables are empty or undefined

Solutions:

  • Verify request format (JSON for body access)
  • Check parameter names match exactly
  • Ensure path/query parameters are properly defined in OpenAPI spec

Performance Issues

Problem: Template expansion is slow

Solutions:

  • Simplify template logic
  • Cache frequently used values
  • Use static responses where dynamic data isn’t needed
  • Profile and optimize custom template functions

For basic HTTP mocking features, see the HTTP Mocking guide. For custom response generation, see the Custom Responses guide.

Advanced Behavior and Simulation

MockForge provides advanced behavior and simulation features that allow you to create realistic, stateful, and resilient API mocks. This guide covers record & playback, stateful behavior simulation, fault injection, latency simulation, and conditional proxying.

Table of Contents

Record & Playback

The record & playback feature allows you to capture real API interactions and convert them into replayable stub mappings.

Quick Start

  1. Start recording the requests the server handles:
mockforge serve --spec api-spec.json --recorder --recorder-db ./mockforge-recordings.db
  1. Convert recordings to stub mappings:
# Convert a specific recording
mockforge recorder convert --recording-id abc123 --output fixtures/user-api.yaml

# Batch convert all recordings
mockforge recorder convert --input recordings.db --output fixtures/ --format yaml

Configuration

core:
  recorder:
    enabled: true
    auto_convert: true
    output_dir: "./fixtures/recorded"
    format: "yaml"
    filters:
      min_status_code: 200
      max_status_code: 299
      exclude_paths:
        - "/health"
        - "/metrics"

API Usage

# Convert via API
curl -X POST http://localhost:9080/api/recorder/convert/abc123 \
  -H "Content-Type: application/json" \
  -d '{"format": "yaml"}'

Stateful Behavior Simulation

Stateful behavior simulation allows responses to change based on previous requests, using state machines to track resource state.

Basic Example

core:
  stateful:
    enabled: true
    state_machines:
      - name: "order_workflow"
        initial_state: "pending"
        states:
          - name: "pending"
            response:
              status_code: 200
              body_template: '{"order_id": "{{resource_id}}", "status": "pending"}'
          - name: "processing"
            response:
              status_code: 200
              body_template: '{"order_id": "{{resource_id}}", "status": "processing"}'
          - name: "shipped"
            response:
              status_code: 200
              body_template: '{"order_id": "{{resource_id}}", "status": "shipped"}'
        resource_id_extract:
          type: "path_param"
          param: "order_id"
        transitions:
          - method: "POST"
            path_pattern: "/api/orders"
            from_state: "initial"
            to_state: "pending"
          - method: "PUT"
            path_pattern: "/api/orders/{order_id}/process"
            from_state: "pending"
            to_state: "processing"

Resource ID Extraction

Extract resource IDs from various sources:

# From path parameter
resource_id_extract:
  type: "path_param"
  param: "order_id"

# From header
resource_id_extract:
  type: "header"
  name: "X-Resource-ID"

# From JSONPath in request body
resource_id_extract:
  type: "json_path"
  path: "$.order.id"

# Composite (tries multiple sources)
resource_id_extract:
  type: "composite"
  extractors:
    - type: "path_param"
      param: "order_id"
    - type: "header"
      name: "X-Order-ID"

Per-Route Fault Injection

Configure fault injection on specific routes with multiple fault types.

Configuration

core:
  routes:
    - path: "/api/payments/process"
      method: "POST"
      fault_injection:
        enabled: true
        probability: 0.05  # 5% chance
        fault_types:
          - type: "http_error"
            status_code: 503
            message: "Service unavailable"
          - type: "timeout"
            duration_ms: 5000
          - type: "connection_error"
            message: "Connection refused"

Fault Types

  • HTTP Error: Return specific status codes
  • Connection Error: Simulate connection failures (HTTP-503 by default; see below for TCP-level)
  • Timeout: Real tokio::sleep(timeout_ms) then 504 Gateway Timeout
  • Partial Response: Truncate responses (chunked-aware: keeps Content-Length on non-chunked, drops the terminator on chunked)
  • Payload Corruption: Corrupt response payloads

Per-Request Matchers (v0.3.125+)

By default, fault probabilities apply to every request. To gate fault injection on properties of the incoming request — useful for targeting specific clients, headers, body sizes, or Transfer-Encoding: chunked traffic without affecting baseline traffic — add a request_matcher block:

fault_injection:
  enabled: true
  http_errors: [503]
  http_error_probability: 0.5     # 50% of *matching* requests get 503
  request_matcher:
    source_ips:
      - "10.0.0.0/8"              # CIDR or bare IP
      - "192.168.1.42"
    headers:
      - name: "x-test"            # case-insensitive name
        value: "yes"              # omit `value` for presence-only
    min_body_size_bytes: 1048576  # only requests with body >= 1 MB
    max_body_size_bytes: 10485760 # AND <= 10 MB (omit either side)
    chunked_only: true            # only Transfer-Encoding: chunked

Semantics: AND across fields, OR within a list. Empty matcher matches every request. Applies to all five fault paths (HTTP errors, timeouts, partial responses, payload corruption, connection errors).

Connection Error Wire-Level Behavior (v0.3.125+)

The connection_error_kind knob picks what “connection error” means at the TCP level:

KindWhat clients see
http_503 (default)HTTP 503 on a healthy connection — application layer only
tcp_resetTCP RST sent at accept time. Clients see ECONNRESET.
tcp_closeTCP FIN at accept time. Clients see EOF before any HTTP response.
fault_injection:
  enabled: true
  connection_errors: true
  connection_error_probability: 0.05
  connection_error_kind: tcp_reset    # http_503 | tcp_reset | tcp_close

The TCP-level kinds wrap the listener with a chaos accept loop, so the fault is per-connection (every request that would have pipelined onto that socket is affected). Auto-installed by mockforge serve when chaos is enabled and the kind is not http_503. Plain HTTP only — TLS path doesn’t yet support TCP-level injection.

For the full reference (every fault config field, hot-reload API, predefined scenarios), see the Chaos Engineering chapter.

Per-Route Latency Simulation

Simulate network latency with various distributions.

Configuration

core:
  routes:
    - path: "/api/search"
      method: "GET"
      latency:
        enabled: true
        probability: 0.8
        distribution: "normal"  # fixed, normal, exponential, uniform
        mean_ms: 500.0
        std_dev_ms: 100.0
        jitter_percent: 15.0

Distributions

  • Fixed: Constant delay with optional jitter
  • Normal: Gaussian distribution (realistic for most APIs)
  • Exponential: Exponential distribution (simulates network delays)
  • Uniform: Random delay within a range

Conditional Proxying

Proxy requests conditionally based on request attributes using expressions.

Availability: conditional proxy rules are applied by the HTTP router when it is built with a ProxyConfig, which today happens through the Rust SDK (MockServerBuilder::proxy(config) in mockforge-sdk). mockforge serve does not read a proxy: section from the config file yet. The YAML below shows the ProxyConfig / ProxyRule field names.

Basic Examples

# ProxyConfig
enabled: true
rules:
  # Proxy admin requests
  - pattern: "/api/admin/*"
    upstream_url: "https://admin-api.example.com"
    condition: "$.user.role == 'admin'"
  
  # Proxy authenticated requests
  - pattern: "/api/protected/*"
    upstream_url: "https://protected-api.example.com"
    condition: "header[authorization] != ''"
  
  # Proxy based on query parameter
  - pattern: "/api/data/*"
    upstream_url: "https://data-api.example.com"
    condition: "query[env] == 'production'"

Condition Types

JSONPath Expressions

condition: "$.user.role == 'admin'"
condition: "$.order.amount > 1000"

Header Checks

condition: "header[authorization] != ''"
condition: "header[user-agent] == 'MobileApp/1.0'"

Query Parameters

condition: "query[env] == 'production'"
condition: "query[version] == 'v2'"

Logical Operators

# AND
condition: "AND(header[authorization] != '', $.user.role == 'admin')"

# OR
condition: "OR(query[env] == 'production', query[env] == 'staging')"

# NOT
condition: "NOT(query[env] == 'development')"

Priority Chain

MockForge processes requests through this priority chain:

  1. Replay - Check for recorded fixtures
  2. Stateful - Check for stateful response handling
  3. Route Chaos - Apply per-route fault injection and latency
  4. Global Fail - Apply global/tag-based failure injection
  5. Proxy - Check for conditional proxying
  6. Mock - Generate mock response from OpenAPI spec
  7. Record - Record request for future replay

MockForge includes many additional advanced features that complement the basic advanced behavior:

For a complete overview, see Advanced Features.

Best Practices

  1. Start simple - Begin with basic configurations and add complexity gradually
  2. Test thoroughly - Verify state transitions and conditions work as expected
  3. Monitor performance - Latency injection can slow down tests
  4. Document conditions - Keep conditional logic well-documented
  5. Use version control - Track configuration changes over time

Examples

See the example configuration file for comprehensive examples of all features.

For more details, see the Advanced Behavior and Simulation documentation.

gRPC Mocking

MockForge provides comprehensive gRPC service mocking with dynamic Protocol Buffer discovery, streaming support, and flexible service registration. This enables testing of gRPC-based microservices and APIs with realistic mock responses.

Overview

MockForge’s gRPC mocking system offers:

  • Dynamic Proto Discovery: Automatically discovers and compiles .proto files from configurable directories
  • Flexible Service Registration: Register and mock any gRPC service without hardcoding
  • Streaming Support: Full support for unary, server streaming, client streaming, and bidirectional streaming
  • Reflection Support: Built-in gRPC reflection for service discovery and testing
  • Template Integration: Use MockForge’s template system for dynamic response generation
  • Advanced Data Synthesis: Intelligent mock data generation with deterministic seeding, relationship awareness, and RAG-driven domain knowledge

Quick Start

Basic gRPC Server

Start a gRPC mock server with default configuration:

# Start with default proto directory (proto/)
mockforge serve --grpc-port 50051

With Custom Proto Directory

# Specify custom proto directory
MOCKFORGE_PROTO_DIR=my-protos mockforge serve --grpc-port 50051

Complete Example

# Start MockForge with HTTP, WebSocket, and gRPC support
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
MOCKFORGE_PROTO_DIR=examples/grpc-protos \
mockforge serve \
  --spec examples/openapi-demo.json \
  --http-port 3000 \
  --ws-port 3001 \
  --grpc-port 50051 \
  --admin --admin-port 9080

Proto File Setup

Directory Structure

MockForge automatically discovers .proto files in a configurable directory:

your-project/
├── proto/                    # Default proto directory
│   ├── user_service.proto   # Will be discovered
│   ├── payment.proto        # Will be discovered
│   └── subdir/
│       └── analytics.proto  # Will be discovered (recursive)
└── examples/
    └── grpc-protos/         # Custom proto directory
        └── service.proto

Sample Proto File

syntax = "proto3";
package mockforge.user;

service UserService {
  rpc GetUser(GetUserRequest) returns (UserResponse);
  rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
  rpc CreateUser(stream CreateUserRequest) returns (UserResponse);
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

message GetUserRequest {
  string user_id = 1;
}

message UserResponse {
  string user_id = 1;
  string name = 2;
  string email = 3;
  int64 created_at = 4;
  Status status = 5;
}

message ListUsersRequest {
  int32 limit = 1;
  string filter = 2;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
}

message ChatMessage {
  string user_id = 1;
  string content = 2;
  int64 timestamp = 3;
}

enum Status {
  UNKNOWN = 0;
  ACTIVE = 1;
  INACTIVE = 2;
  SUSPENDED = 3;
}

Dynamic Response Generation

MockForge generates responses automatically based on your proto message schemas, with support for templates and custom logic.

Automatic Response Generation

For basic use cases, MockForge generates responses from proto schemas:

  • Strings: Random realistic values
  • Integers: Random numbers in appropriate ranges
  • Timestamps: Current time or future dates
  • Enums: Random valid enum values
  • Messages: Nested objects with generated data
  • Repeated fields: Arrays with multiple generated items

Template-Enhanced Responses

Use MockForge templates in proto comments for custom responses:

message UserResponse {
  string user_id = 1; // {{uuid}}
  string name = 2; // {{request.user_id == "123" ? "John Doe" : "Jane Smith"}}
  string email = 3; // {{name | replace(" ", ".") | lower}}@example.com
  int64 created_at = 4; // {{now}}
  Status status = 5; // ACTIVE
}

Request Context Access

Access request data in templates:

message UserResponse {
  string user_id = 1; // {{request.user_id}}
  string requested_by = 2; // {{request.metadata.user_id}}
  string message = 3; // User {{request.user_id}} was retrieved
}

Testing gRPC Services

Using gRPC CLI Tools

# Install grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest

# List available services
grpcurl -plaintext localhost:50051 list

# Call a unary method
grpcurl -plaintext -d '{"user_id": "123"}' \
  localhost:50051 mockforge.user.UserService/GetUser

# Call a server streaming method
grpcurl -plaintext -d '{"limit": 5}' \
  localhost:50051 mockforge.user.UserService/ListUsers

# Call a client streaming method
echo '{"name": "Alice", "email": "[email protected]"}' | \
grpcurl -plaintext -d @ \
  localhost:50051 mockforge.user.UserService/CreateUser

grpcui (Web Interface)

# Install grpcui
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest

# Start web interface
grpcui -plaintext localhost:50051

# Open http://localhost:2633 in your browser

Programmatic Testing

Node.js with grpc-js

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync(
  'proto/user_service.proto',
  {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
  }
);

const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const client = new protoDescriptor.mockforge.user.UserService(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

// Unary call
client.GetUser({ user_id: '123' }, (error, response) => {
  if (error) {
    console.error('Error:', error);
  } else {
    console.log('Response:', response);
  }
});

// Server streaming
const stream = client.ListUsers({ limit: 5 });
stream.on('data', (response) => {
  console.log('User:', response);
});
stream.on('end', () => {
  console.log('Stream ended');
});

Python with grpcio

import grpc
from user_service_pb2 import GetUserRequest
from user_service_pb2_grpc import UserServiceStub

channel = grpc.insecure_channel('localhost:50051')
stub = UserServiceStub(channel)

# Unary call
request = GetUserRequest(user_id='123')
response = stub.GetUser(request)
print(f"User: {response.name}, Email: {response.email}")

# Streaming
for user in stub.ListUsers(ListUsersRequest(limit=5)):
    print(f"User: {user.name}")

Advanced Configuration

Custom Response Mappings

Create custom response logic by implementing service handlers:

#![allow(unused)]
fn main() {
use mockforge_grpc::{ServiceRegistry, ServiceImplementation};
use std::collections::HashMap;

struct CustomUserService {
    user_data: HashMap<String, UserResponse>,
}

impl ServiceImplementation for CustomUserService {
    fn handle_unary(&self, method: &str, request: &[u8]) -> Vec<u8> {
        match method {
            "GetUser" => {
                let req: GetUserRequest = prost::Message::decode(request).unwrap();
                let response = self.user_data.get(&req.user_id)
                    .cloned()
                    .unwrap_or_else(|| UserResponse {
                        user_id: req.user_id,
                        name: "Unknown User".to_string(),
                        email: "[email protected]".to_string(),
                        created_at: std::time::SystemTime::now()
                            .duration_since(std::time::UNIX_EPOCH)
                            .unwrap().as_secs() as i64,
                        status: Status::Unknown as i32,
                    });
                let mut buf = Vec::new();
                response.encode(&mut buf).unwrap();
                buf
            }
            _ => Vec::new(),
        }
    }
}
}

Environment Variables

MOCKFORGE_PROTO_DIR=proto/   # Directory containing .proto files
MOCKFORGE_GRPC_PORT=50051    # gRPC server port
MOCKFORGE_GRPC_HOST=0.0.0.0  # Bind address

Per-protocol latency is configured via the chaos engine, not gRPC-specific env vars. To inject latency on gRPC calls, enable chaos engineering — it applies uniformly across HTTP, WS, and gRPC.

Configuration File

grpc:
  enabled: true
  port: 50051
  host: "0.0.0.0"
  proto_dir: "proto/"

Reflection is enabled by default at the runtime level via DynamicGrpcConfig::enable_reflection. Most users don’t need to disable it; if you do, configure programmatically when embedding MockForge as a library — there’s no top-level YAML knob for it yet.

For latency injection, partial-response simulation, or fault injection on gRPC calls, use the chaos engine — it hooks every protocol with the same config surface.

Streaming Support

MockForge supports all gRPC streaming patterns:

Unary (Request → Response)

rpc GetUser(GetUserRequest) returns (UserResponse);

Standard request-response pattern used for simple operations.

Server Streaming (Request → Stream of Responses)

rpc ListUsers(ListUsersRequest) returns (stream UserResponse);

Single request that returns multiple responses over time.

Client Streaming (Stream of Requests → Response)

rpc CreateUsers(stream CreateUserRequest) returns (UserSummary);

Multiple requests sent as a stream, single response returned.

Bidirectional Streaming (Stream ↔ Stream)

rpc Chat(stream ChatMessage) returns (stream ChatMessage);

Both client and server can send messages independently.

Error Handling

gRPC Status Codes

MockForge supports all standard gRPC status codes:

// In proto comments for custom error responses
rpc GetUser(GetUserRequest) returns (UserResponse);
// @error NOT_FOUND User not found
// @error INVALID_ARGUMENT Invalid user ID format
// @error INTERNAL Server error occurred

Custom Error Responses

#![allow(unused)]
fn main() {
// Custom error handling
fn handle_unary(&self, method: &str, request: &[u8]) -> Result<Vec<u8>, tonic::Status> {
    match method {
        "GetUser" => {
            let req: GetUserRequest = prost::Message::decode(request)?;

            if !is_valid_user_id(&req.user_id) {
                return Err(tonic::Status::invalid_argument("Invalid user ID"));
            }

            match self.get_user(&req.user_id) {
                Some(user) => {
                    let mut buf = Vec::new();
                    user.encode(&mut buf)?;
                    Ok(buf)
                }
                None => Err(tonic::Status::not_found("User not found")),
            }
        }
        _ => Err(tonic::Status::unimplemented("Method not implemented")),
    }
}
}

Integration Patterns

Microservices Testing

# Start multiple gRPC services
MOCKFORGE_PROTO_DIR=user-proto mockforge serve --grpc-port 50051 &
MOCKFORGE_PROTO_DIR=payment-proto mockforge serve --grpc-port 50052 &
MOCKFORGE_PROTO_DIR=inventory-proto mockforge serve --grpc-port 50053 &

# Test service communication
grpcurl -plaintext localhost:50051 mockforge.user.UserService/GetUser \
  -d '{"user_id": "123"}'

Load Testing

# Simple load test with hey
hey -n 1000 -c 10 \
  grpcurl -plaintext -d '{"user_id": "123"}' \
    localhost:50051 mockforge.user.UserService/GetUser

# Advanced load testing with ghz
ghz --insecure \
    --proto proto/user_service.proto \
    --call mockforge.user.UserService.GetUser \
    --data '{"user_id": "123"}' \
    --concurrency 10 \
    --total 1000 \
    localhost:50051

CI/CD Integration

# .github/workflows/test.yml
name: gRPC Tests
on: [push, pull_request]

jobs:
  grpc-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
      - name: Start MockForge
        run: |
          cargo run --bin mockforge-cli -- serve --grpc-port 50051 &
          sleep 5
      - name: Run gRPC Tests
        run: |
          npm install -g grpcurl
          grpcurl -plaintext localhost:50051 list
          # Add your test commands here

Best Practices

Proto File Organization

  1. Clear Package Names: Use descriptive package names that reflect service domains
  2. Consistent Naming: Follow protobuf naming conventions
  3. Versioning: Include version information in package names when appropriate
  4. Documentation: Add comments to proto files for better API documentation

Service Design

  1. Appropriate Streaming: Choose the right streaming pattern for your use case
  2. Error Handling: Define clear error conditions and status codes
  3. Pagination: Implement pagination for large result sets
  4. Backwards Compatibility: Design for evolution and backwards compatibility

Testing Strategies

  1. Unit Tests: Test individual service methods
  2. Integration Tests: Test service interactions
  3. Load Tests: Verify performance under load
  4. Chaos Tests: Test failure scenarios and recovery

Performance Optimization

  1. Response Caching: Cache frequently requested data
  2. Connection Pooling: Reuse gRPC connections
  3. Async Processing: Use async operations for I/O bound tasks
  4. Memory Management: Monitor and optimize memory usage

Troubleshooting

Common Issues

Proto files not found: Check MOCKFORGE_PROTO_DIR environment variable and directory permissions

Service not available: Verify proto compilation succeeded and service names match

Connection refused: Ensure gRPC port is accessible and not blocked by firewall

Template errors: Check template syntax and available context variables

Debug Commands

# Check proto compilation
cargo build --verbose

# List available services
grpcurl -plaintext localhost:50051 list

# Check service methods
grpcurl -plaintext localhost:50051 describe mockforge.user.UserService

# Test with verbose output
grpcurl -plaintext -v -d '{"user_id": "123"}' \
  localhost:50051 mockforge.user.UserService/GetUser

Log Analysis

# View gRPC logs
tail -f mockforge.log | grep -i grpc

# Count requests by service
grep "grpc.*call" mockforge.log | cut -d' ' -f5 | sort | uniq -c

# Monitor errors
grep -i "grpc.*error" mockforge.log

For detailed implementation guides, see:

Protocol Buffers

Protocol Buffers (protobuf) are the interface definition language used by gRPC services. MockForge provides comprehensive support for working with protobuf files, including automatic discovery, compilation, and dynamic service generation.

Understanding Proto Files

Basic Structure

A .proto file defines the service interface and message formats:

syntax = "proto3";

package myapp.user;

import "google/protobuf/timestamp.proto";

// Service definition
service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);
  rpc CreateUser(CreateUserRequest) returns (User);
  rpc UpdateUser(UpdateUserRequest) returns (User);
  rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty);
}

// Message definitions
message GetUserRequest {
  string user_id = 1;
}

message User {
  string user_id = 1;
  string email = 2;
  string name = 3;
  google.protobuf.Timestamp created_at = 4;
  google.protobuf.Timestamp updated_at = 5;
  UserStatus status = 6;
  repeated string roles = 7;
}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
  string filter = 3;
}

message CreateUserRequest {
  string email = 1;
  string name = 2;
  repeated string roles = 3;
}

message UpdateUserRequest {
  string user_id = 1;
  string email = 2;
  string name = 3;
  repeated string roles = 4;
}

message DeleteUserRequest {
  string user_id = 1;
}

enum UserStatus {
  UNKNOWN = 0;
  ACTIVE = 1;
  INACTIVE = 2;
  SUSPENDED = 3;
}

Key Components

Syntax Declaration

syntax = "proto3";

Declares the protobuf version. MockForge supports proto3.

Package Declaration

package myapp.user;

Defines the namespace for the service and messages.

Imports

import "google/protobuf/timestamp.proto";

Imports common protobuf types and other proto files.

Service Definition

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  // ... more methods
}

Defines the RPC methods available in the service.

Message Definitions

message User {
  string user_id = 1;
  string email = 2;
  // ... more fields
}

Defines the structure of data exchanged between client and server.

Enum Definitions

enum UserStatus {
  UNKNOWN = 0;
  ACTIVE = 1;
  // ... more values
}

Defines enumerated types with named constants.

Field Types

Scalar Types

Proto TypeGo TypeJava TypeC++ TypeNotes
doublefloat64doubledouble
floatfloat32floatfloat
int32int32intint32Uses variable-length encoding
int64int64longint64Uses variable-length encoding
uint32uint32intuint32Uses variable-length encoding
uint64uint64longuint64Uses variable-length encoding
sint32int32intint32Uses zigzag encoding
sint64int64longint64Uses zigzag encoding
fixed32uint32intuint32Always 4 bytes
fixed64uint64longuint64Always 8 bytes
sfixed32int32intint32Always 4 bytes
sfixed64int64longint64Always 8 bytes
boolboolbooleanbool
stringstringStringstringUTF-8 encoded
bytes[]byteByteStringstring

Repeated Fields

message SearchResponse {
  repeated Result results = 1;
}

Creates an array/list of the specified type.

Nested Messages

message Address {
  string street = 1;
  string city = 2;
  string country = 3;
}

message Person {
  string name = 1;
  Address address = 2;
}

Messages can contain other messages as fields.

Oneof Fields

message Person {
  string name = 1;
  oneof contact_info {
    string email = 2;
    string phone = 3;
  }
}

Only one of the specified fields can be set at a time.

Maps

message Config {
  map<string, string> settings = 1;
}

Creates a key-value map structure.

Service Patterns

Unary RPC

service Calculator {
  rpc Add(AddRequest) returns (AddResponse);
}

Standard request-response pattern.

Server Streaming

service NotificationService {
  rpc Subscribe(SubscribeRequest) returns (stream Notification);
}

Server sends multiple responses for a single request.

Client Streaming

service UploadService {
  rpc Upload(stream UploadChunk) returns (UploadResponse);
}

Client sends multiple requests, server responds once.

Bidirectional Streaming

service ChatService {
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

Both client and server can send messages independently.

Proto File Organization

Directory Structure

proto/
├── user/
│   ├── v1/
│   │   ├── user.proto
│   │   └── user_service.proto
│   └── v2/
│       ├── user.proto
│       └── user_service.proto
├── payment/
│   ├── payment.proto
│   └── payment_service.proto
└── common/
    ├── types.proto
    └── errors.proto

Versioning

// user/v1/user.proto
syntax = "proto3";
package myapp.user.v1;

// Version-specific message
message User {
  string id = 1;
  string name = 2;
  string email = 3;
}
// user/v2/user.proto
syntax = "proto3";
package myapp.user.v2;

// Extended version with new fields
message User {
  string id = 1;
  string name = 2;
  string email = 3;
  string phone = 4;  // New field
  repeated string tags = 5;  // New field
}

MockForge Integration

Automatic Discovery

MockForge automatically discovers .proto files in the configured directory:

# Default proto directory
mockforge serve --grpc-port 50051

# Custom proto directory
MOCKFORGE_PROTO_DIR=my-protos mockforge serve --grpc-port 50051

Service Registration

MockForge automatically registers all discovered services:

# List available services
grpcurl -plaintext localhost:50051 list

# Output:
# grpc.reflection.v1alpha.ServerReflection
# myapp.user.UserService
# myapp.payment.PaymentService

Dynamic Response Generation

MockForge generates responses based on proto message schemas:

message UserResponse {
  string user_id = 1;    // Generates UUID
  string name = 2;       // Generates random name
  string email = 3;      // Generates valid email
  int64 created_at = 4;  // Generates timestamp
  UserStatus status = 5; // Random enum value
}

Template Support

Use MockForge templates for custom responses:

message UserResponse {
  string user_id = 1;    // {{uuid}}
  string name = 2;       // {{request.user_id == "123" ? "John Doe" : "Jane Smith"}}
  string email = 3;      // {{name | replace(" ", ".") | lower}}@example.com
  int64 created_at = 4;  // {{now}}
  UserStatus status = 5; // ACTIVE
}

Best Practices

Naming Conventions

  1. Packages: Use lowercase with dots (e.g., myapp.user.v1)
  2. Services: Use PascalCase with “Service” suffix (e.g., UserService)
  3. Messages: Use PascalCase (e.g., UserProfile)
  4. Fields: Use snake_case (e.g., user_id, created_at)
  5. Enums: Use PascalCase for type, SCREAMING_SNAKE_CASE for values

Field Numbering

  1. Reserve numbers: Don’t reuse field numbers from deleted fields
  2. Start from 1: Field numbers start from 1
  3. Gap for extensions: Leave gaps for future extensions
  4. Document reservations: Comment reserved field numbers
message User {
  string user_id = 1;
  string name = 2;
  string email = 3;
  // reserved 4, 5, 6;  // Reserved for future use
  int64 created_at = 7;
}

Import Organization

  1. Standard imports: Import well-known protobuf types first
  2. Local imports: Import project-specific proto files
  3. Relative paths: Use relative paths for local imports
syntax = "proto3";

import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";

import "common/types.proto";
import "user/profile.proto";

package myapp.user;

Documentation

  1. Service comments: Document what each service does
  2. Method comments: Explain each RPC method
  3. Field comments: Describe field purposes and constraints
  4. Enum comments: Document enum value meanings
// User management service
service UserService {
  // Get a user by ID
  rpc GetUser(GetUserRequest) returns (User);

  // List users with pagination
  rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
}

message User {
  string user_id = 1;  // Unique identifier for the user
  string email = 2;    // User's email address (must be valid)
  UserStatus status = 3; // Current account status
}

enum UserStatus {
  UNKNOWN = 0;   // Default value
  ACTIVE = 1;    // Account is active
  INACTIVE = 2;  // Account is deactivated
  SUSPENDED = 3; // Account is temporarily suspended
}

Migration and Evolution

Adding Fields

// Original
message User {
  string user_id = 1;
  string name = 2;
}

// Extended (backwards compatible)
message User {
  string user_id = 1;
  string name = 2;
  string email = 3;      // New field
  bool active = 4;       // New field
}

Reserved Fields

message User {
  reserved 5, 6, 7;        // Reserved for future use
  reserved "old_field";    // Reserved field name

  string user_id = 1;
  string name = 2;
  string email = 3;
}

Versioning Strategy

  1. Package versioning: Include version in package name
  2. Service evolution: Extend services with new methods
  3. Deprecation notices: Mark deprecated fields
  4. Breaking changes: Create new service versions

Validation

Proto File Validation

# Validate proto syntax
protoc --proto_path=. --error_format=json myproto.proto

# Generate descriptors
protoc --proto_path=. --descriptor_set_out=descriptor.pb myproto.proto

MockForge Integration Testing

# Test proto compilation
MOCKFORGE_PROTO_DIR=my-protos cargo build

# Verify service discovery
mockforge serve --grpc-port 50051 &
sleep 2
grpcurl -plaintext localhost:50051 list

Cross-Language Compatibility

# Generate code for multiple languages
protoc --proto_path=. \
  --go_out=. \
  --java_out=. \
  --python_out=. \
  --cpp_out=. \
  myproto.proto

Troubleshooting

Common Proto Issues

Import resolution: Ensure all imported proto files are available in the proto path

Field conflicts: Check for duplicate field numbers or names within messages

Circular imports: Avoid circular dependencies between proto files

Syntax errors: Use protoc to validate proto file syntax

MockForge-Specific Issues

Services not discovered: Check proto directory configuration and file permissions

Invalid responses: Verify proto message definitions match expected schemas

Compilation failures: Check for proto syntax errors and missing dependencies

Template errors: Ensure template variables are properly escaped in proto comments

Debug Commands

# Check proto file discovery
find proto/ -name "*.proto" -type f

# Validate proto files
for file in $(find proto/ -name "*.proto"); do
  echo "Validating $file..."
  protoc --proto_path=. --error_format=json "$file" > /dev/null
done

# Test service compilation
MOCKFORGE_PROTO_DIR=proto/ cargo check -p mockforge-grpc

# Inspect generated code
cargo doc --open --package mockforge-grpc

Protocol Buffers provide a robust foundation for gRPC service definitions. By following these guidelines and leveraging MockForge’s dynamic discovery capabilities, you can create well-structured, maintainable, and testable gRPC services.

Streaming

gRPC supports four fundamental communication patterns, with three involving streaming. MockForge provides comprehensive support for all streaming patterns, enabling realistic testing of real-time and batch data scenarios.

Streaming Patterns

Unary (Request → Response)

Standard request-response pattern - one message in, one message out.

Server Streaming (Request → Stream of Responses)

Single request initiates a stream of responses from server to client.

Client Streaming (Stream of Requests → Response)

Client sends multiple messages, server responds once with aggregated result.

Bidirectional Streaming (Stream ↔ Stream)

Both client and server can send messages independently and simultaneously.

Server Streaming

Basic Server Streaming

service NotificationService {
  rpc Subscribe(SubscribeRequest) returns (stream Notification);
}

message SubscribeRequest {
  repeated string topics = 1;
  SubscriptionType type = 2;
}

message Notification {
  string topic = 1;
  string message = 2;
  google.protobuf.Timestamp timestamp = 3;
  Severity severity = 4;
}

enum SubscriptionType {
  REALTIME = 0;
  BATCH = 1;
}

enum Severity {
  INFO = 0;
  WARNING = 1;
  ERROR = 2;
  CRITICAL = 3;
}

MockForge Configuration

Server streaming generates multiple responses based on configuration:

// Basic server streaming - fixed number of responses
{"ts":0,"dir":"out","text":"{\"topic\":\"system\",\"message\":\"Connected\",\"severity\":\"INFO\"}"}
{"ts":1000,"dir":"out","text":"{\"topic\":\"user\",\"message\":\"New user registered\",\"severity\":\"INFO\"}"}
{"ts":2000,"dir":"out","text":"{\"topic\":\"payment\",\"message\":\"Payment processed\",\"severity\":\"INFO\"}"}
{"ts":3000,"dir":"out","text":"{\"topic\":\"system\",\"message\":\"Maintenance scheduled\",\"severity\":\"WARNING\"}"}

Dynamic Server Streaming

// Template-based dynamic responses
{"ts":0,"dir":"out","text":"{\"topic\":\"{{request.topics[0]}}\",\"message\":\"Subscribed to {{request.topics.length}} topics\",\"timestamp\":\"{{now}}\"}"}
{"ts":1000,"dir":"out","text":"{\"topic\":\"{{randFromArray request.topics}}\",\"message\":\"{{randParagraph}}\",\"timestamp\":\"{{now}}\"}"}
{"ts":2000,"dir":"out","text":"{\"topic\":\"{{randFromArray request.topics}}\",\"message\":\"{{randSentence}}\",\"timestamp\":\"{{now}}\"}"}
{"ts":5000,"dir":"out","text":"{\"topic\":\"system\",\"message\":\"Stream ending\",\"timestamp\":\"{{now}}\"}"}

Testing Server Streaming

Using grpcurl

# Test server streaming
grpcurl -plaintext -d '{"topics": ["user", "payment"], "type": "REALTIME"}' \
  localhost:50051 myapp.NotificationService/Subscribe

Using Node.js

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync('proto/notification.proto');
const proto = grpc.loadPackageDefinition(packageDefinition);

const client = new proto.myapp.NotificationService(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

const call = client.Subscribe({
  topics: ['user', 'payment'],
  type: 'REALTIME'
});

call.on('data', (notification) => {
  console.log('Notification:', notification);
});

call.on('end', () => {
  console.log('Stream ended');
});

call.on('error', (error) => {
  console.error('Error:', error);
});

Client Streaming

Basic Client Streaming

service UploadService {
  rpc UploadFile(stream FileChunk) returns (UploadResponse);
}

message FileChunk {
  bytes data = 1;
  int32 sequence = 2;
  bool is_last = 3;
}

message UploadResponse {
  string file_id = 1;
  int64 total_size = 2;
  string checksum = 3;
  UploadStatus status = 4;
}

enum UploadStatus {
  SUCCESS = 0;
  FAILED = 1;
  PARTIAL = 2;
}

MockForge Configuration

Client streaming processes multiple incoming messages and returns a single response:

// Client streaming - processes multiple chunks
{"ts":0,"dir":"in","text":".*","response":"{\"file_id\":\"{{uuid}}\",\"total_size\":1024,\"status\":\"SUCCESS\"}"}

Advanced Client Streaming

// Process chunks and maintain state
{"ts":0,"dir":"in","text":"{\"sequence\":0}","response":"Chunk 0 received","state":"uploading","chunks":1}
{"ts":0,"dir":"in","text":"{\"sequence\":1}","response":"Chunk 1 received","chunks":"{{request.ws.state.chunks + 1}}"}
{"ts":0,"dir":"in","text":"{\"is_last\":true}","response":"{\"file_id\":\"{{uuid}}\",\"total_size\":\"{{request.ws.state.chunks * 1024}}\",\"status\":\"SUCCESS\"}"}

Testing Client Streaming

Using grpcurl

# Send multiple messages for client streaming
echo '{"data": "chunk1", "sequence": 0}' | \
grpcurl -plaintext -d @ localhost:50051 myapp.UploadService/UploadFile

echo '{"data": "chunk2", "sequence": 1}' | \
grpcurl -plaintext -d @ localhost:50051 myapp.UploadService/UploadFile

echo '{"data": "chunk3", "sequence": 2, "is_last": true}' | \
grpcurl -plaintext -d @ localhost:50051 myapp.UploadService/UploadFile

Using Python

import grpc
from upload_pb2 import FileChunk
from upload_pb2_grpc import UploadServiceStub

def generate_chunks():
    # Simulate file chunks
    chunks = [
        b"chunk1",
        b"chunk2",
        b"chunk3"
    ]

    for i, chunk in enumerate(chunks):
        yield FileChunk(
            data=chunk,
            sequence=i,
            is_last=(i == len(chunks) - 1)
        )

channel = grpc.insecure_channel('localhost:50051')
stub = UploadServiceStub(channel)

response = stub.UploadFile(generate_chunks())
print(f"Upload result: {response}")

Bidirectional Streaming

Basic Bidirectional Streaming

service ChatService {
  rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

message ChatMessage {
  string user_id = 1;
  string content = 2;
  MessageType type = 3;
  google.protobuf.Timestamp timestamp = 4;
}

enum MessageType {
  TEXT = 0;
  JOIN = 1;
  LEAVE = 2;
  SYSTEM = 3;
}

MockForge Configuration

Bidirectional streaming handles both incoming and outgoing messages:

// Welcome message on connection
{"ts":0,"dir":"out","text":"{\"user_id\":\"system\",\"content\":\"Welcome to chat!\",\"type\":\"SYSTEM\"}"}

// Handle join messages
{"ts":0,"dir":"in","text":"{\"type\":\"JOIN\"}","response":"{\"user_id\":\"system\",\"content\":\"{{request.ws.message.user_id}} joined the chat\",\"type\":\"SYSTEM\"}"}

// Handle text messages
{"ts":0,"dir":"in","text":"{\"type\":\"TEXT\"}","response":"{\"user_id\":\"{{request.ws.message.user_id}}\",\"content\":\"{{request.ws.message.content}}\",\"type\":\"TEXT\"}"}

// Handle leave messages
{"ts":0,"dir":"in","text":"{\"type\":\"LEAVE\"}","response":"{\"user_id\":\"system\",\"content\":\"{{request.ws.message.user_id}} left the chat\",\"type\":\"SYSTEM\"}"}

// Periodic system messages
{"ts":30000,"dir":"out","text":"{\"user_id\":\"system\",\"content\":\"Server uptime: {{randInt 1 24}} hours\",\"type\":\"SYSTEM\"}"}

Advanced Bidirectional Patterns

// State-aware responses
{"ts":0,"dir":"in","text":".*","condition":"{{!request.ws.state.authenticated}}","response":"Please authenticate first"}
{"ts":0,"dir":"in","text":"AUTH","response":"Authenticated","state":"authenticated"}

{"ts":0,"dir":"in","text":".*","condition":"{{request.ws.state.authenticated}}","response":"{{request.ws.message}}"}

{"ts":0,"dir":"in","text":"HELP","response":"Available commands: MSG, QUIT, STATUS"}
{"ts":0,"dir":"in","text":"STATUS","response":"Connected users: {{randInt 1 50}}"}
{"ts":0,"dir":"in","text":"QUIT","response":"Goodbye!","close":true}

Testing Bidirectional Streaming

Using Node.js

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync('proto/chat.proto');
const proto = grpc.loadPackageDefinition(packageDefinition);

const client = new proto.myapp.ChatService(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

const call = client.Chat();

// Handle incoming messages
call.on('data', (message) => {
  console.log('Received:', message);
});

// Send messages
setInterval(() => {
  call.write({
    user_id: 'user123',
    content: 'Hello from client',
    type: 'TEXT'
  });
}, 2000);

// Send join message
call.write({
  user_id: 'user123',
  content: 'Joined chat',
  type: 'JOIN'
});

// Handle stream end
call.on('end', () => {
  console.log('Stream ended');
});

// Close after 30 seconds
setTimeout(() => {
  call.write({
    user_id: 'user123',
    content: 'Leaving chat',
    type: 'LEAVE'
  });
  call.end();
}, 30000);

Streaming Configuration

Configuration

Streaming behavior is YAML-only — there are no MOCKFORGE_GRPC_STREAM_* env vars. Configure under grpc.streaming.*:

grpc:
  port: 50051
  streaming:
    stream_timeout_ms: 30000
    max_stream_messages: 1000
    buffer_size: 1024

For per-call latency, use the chaos engine — it applies uniformly across HTTP / WS / gRPC.

Stream Control Templates

// Conditional streaming
{"ts":0,"dir":"out","text":"Starting stream","condition":"{{request.stream_enabled}}"}
{"ts":1000,"dir":"out","text":"Stream data","condition":"{{request.ws.state.active}}"}
{"ts":0,"dir":"out","text":"Stream ended","condition":"{{request.ws.message.type === 'END'}}","close":true}

// Dynamic intervals
{"ts":"{{randInt 1000 5000}}","dir":"out","text":"Random interval message"}
{"ts":"{{request.interval || 2000}}","dir":"out","text":"Custom interval message"}

Performance Considerations

Memory Management

// Limit message history
{"ts":0,"dir":"in","text":".*","condition":"{{(request.ws.state.messageCount || 0) < 100}}","response":"Message received","messageCount":"{{(request.ws.state.messageCount || 0) + 1}}"}
{"ts":0,"dir":"in","text":".*","condition":"{{(request.ws.state.messageCount || 0) >= 100}}","response":"Message limit reached"}

Connection Limits

// Global connection tracking (requires custom implementation)
{"ts":0,"dir":"out","text":"Connection {{request.ws.connectionId}} established"}
{"ts":300000,"dir":"out","text":"Connection timeout","close":true}

Load Balancing

// Simulate load balancer behavior
{"ts":"{{randInt 100 1000}}","dir":"out","text":"Response from server {{randInt 1 3}}"}
{"ts":"{{randInt 2000 5000}}","dir":"out","text":"Health check from server {{randInt 1 3}}"}

Error Handling in Streams

Stream Errors

// Handle invalid messages
{"ts":0,"dir":"in","text":"","response":"Empty message not allowed"}
{"ts":0,"dir":"in","text":".{500,}","response":"Message too long (max 500 chars)"}

// Simulate network errors
{"ts":5000,"dir":"out","text":"Network error occurred","error":true,"close":true}

Recovery Patterns

// Automatic reconnection
{"ts":0,"dir":"out","text":"Connection lost, attempting reconnect..."}
{"ts":2000,"dir":"out","text":"Reconnected successfully"}
{"ts":100,"dir":"out","text":"Resuming stream from message {{request.ws.state.lastMessageId}}"}

Testing Strategies

Unit Testing Streams

// test-streaming.js
const { expect } = require('chai');

describe('gRPC Streaming', () => {
  it('should handle server streaming', (done) => {
    const call = client.subscribeNotifications({ topics: ['test'] });

    let messageCount = 0;
    call.on('data', (notification) => {
      messageCount++;
      expect(notification).to.have.property('topic');
      expect(notification).to.have.property('message');
    });

    call.on('end', () => {
      expect(messageCount).to.be.greaterThan(0);
      done();
    });

    // End test after 5 seconds
    setTimeout(() => call.cancel(), 5000);
  });

  it('should handle client streaming', (done) => {
    const call = client.uploadFile((error, response) => {
      expect(error).to.be.null;
      expect(response).to.have.property('file_id');
      expect(response.status).to.equal('SUCCESS');
      done();
    });

    // Send test chunks
    call.write({ data: Buffer.from('test'), sequence: 0 });
    call.write({ data: Buffer.from('data'), sequence: 1, is_last: true });
    call.end();
  });
});

Load Testing

#!/bin/bash
# load-test-streams.sh

CONCURRENT_STREAMS=10
DURATION=60

echo "Load testing $CONCURRENT_STREAMS concurrent streams for ${DURATION}s"

for i in $(seq 1 $CONCURRENT_STREAMS); do
  node stream-client.js &
done

# Wait for test duration
sleep $DURATION

# Kill all clients
pkill -f stream-client.js

echo "Load test completed"

Best Practices

Stream Design

  1. Appropriate Patterns: Choose the right streaming pattern for your use case
  2. Message Size: Keep individual messages reasonably sized
  3. Heartbeat Messages: Include periodic keepalive messages for long-running streams
  4. Error Recovery: Implement proper error handling and recovery mechanisms

Performance Optimization

  1. Buffering: Use appropriate buffer sizes for your throughput requirements
  2. Compression: Enable compression for large message streams
  3. Connection Reuse: Reuse connections when possible
  4. Resource Limits: Set appropriate limits on concurrent streams and message rates

Monitoring and Debugging

  1. Stream Metrics: Monitor stream duration, message counts, and error rates
  2. Logging: Enable detailed logging for debugging streaming issues
  3. Tracing: Implement request tracing across stream messages
  4. Health Checks: Regular health checks for long-running streams

Client Compatibility

  1. Protocol Versions: Ensure compatibility with different gRPC versions
  2. Language Support: Test with multiple client language implementations
  3. Network Conditions: Test under various network conditions (latency, packet loss)
  4. Browser Support: Consider WebSocket fallback for web clients

Troubleshooting

Common Streaming Issues

Stream doesn’t start: Check proto file definitions and service registration

Messages not received: Verify message encoding and template syntax

Stream hangs: Check for proper stream termination and timeout settings

Performance degradation: Monitor resource usage and adjust buffer sizes

Client disconnects: Implement proper heartbeat and reconnection logic

Debug Commands

# Monitor active streams
grpcurl -plaintext localhost:50051 list

# Check stream status
netstat -tlnp | grep :50051

# View stream logs
tail -f mockforge.log | grep -E "(stream|grpc)"

# Test basic connectivity
grpcurl -plaintext localhost:50051 grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo

Performance Profiling

# Profile gRPC performance
cargo flamegraph --bin mockforge-cli -- serve --grpc-port 50051

# Monitor system resources
htop -p $(pgrep mockforge)

# Network monitoring
iftop -i lo

Streaming patterns enable powerful real-time communication scenarios. MockForge’s comprehensive streaming support allows you to create sophisticated mock environments that accurately simulate production streaming services for thorough testing and development.

Advanced Data Synthesis

MockForge provides sophisticated data synthesis capabilities that go beyond simple random data generation. The advanced data synthesis system combines intelligent field inference, deterministic seeding, relationship-aware generation, and cross-endpoint validation to create realistic, coherent, and reproducible test data.

Overview

The advanced data synthesis system consists of four main components:

  1. Smart Mock Generator - Intelligent field-based mock data generation with deterministic seeding
  2. Schema Graph Extraction - Automatic discovery of relationships from protobuf schemas
  3. RAG-Driven Synthesis - Domain-aware data generation using Retrieval-Augmented Generation
  4. Validation Framework - Cross-endpoint consistency and integrity validation

These components work together to provide enterprise-grade test data generation that maintains referential integrity across your entire gRPC service ecosystem.

Smart Mock Generator

The Smart Mock Generator provides intelligent mock data generation based on field names, types, and patterns. It automatically detects the intent behind field names and generates appropriate realistic data.

Field Name Intelligence

The generator automatically infers appropriate data types based on field names:

Field PatternGenerated Data TypeExample Values
email, email_addressRealistic email addresses[email protected], [email protected]
phone, mobile, phone_numberFormatted phone numbers+1-555-0123, (555) 123-4567
id, user_id, order_idSequential or UUID-based IDsuser_001, 550e8400-e29b-41d4-a716-446655440000
name, first_name, last_nameRealistic namesJohn Doe, Alice, Johnson
created_at, updated_at, timestampISO timestamps2023-10-15T14:30:00Z
latitude, longitudeGeographic coordinates40.7128, -74.0060
url, websiteValid URLshttps://example.com
token, api_keySecurity tokenssk_live_4eC39HqLyjWDarjtT1zdp7dc

Deterministic Generation

For reproducible test fixtures, the Smart Mock Generator supports deterministic seeding:

#![allow(unused)]
fn main() {
use mockforge_grpc::reflection::smart_mock_generator::{SmartMockGenerator, SmartMockConfig};

// Create a deterministic generator with a fixed seed
let mut generator = SmartMockGenerator::new_with_seed(
    SmartMockConfig::default(),
    12345 // seed value
);

// Generate reproducible data
let uuid1 = generator.generate_uuid();
let email = generator.generate_random_string(10);

// Reset to regenerate same data
generator.reset();
let uuid2 = generator.generate_uuid(); // Same as uuid1
}

This ensures that your tests produce consistent results across different runs and environments.

Schema Graph Extraction

The schema graph extraction system analyzes your protobuf definitions to automatically discover relationships and foreign key patterns between entities.

Foreign Key Detection

The system uses naming conventions to detect foreign key relationships:

message Order {
  string id = 1;
  string user_id = 2;     // → Detected as foreign key to User
  string customer_ref = 3; // → Detected as reference to Customer  
  int64 timestamp = 4;
}

message User {
  string id = 1;          // → Detected as primary key
  string name = 2;
  string email = 3;
}

Common Foreign Key Patterns:

  • user_id → references User entity
  • orderId → references Order entity
  • customer_ref → references Customer entity

Relationship Types

The system identifies various relationship types:

  • Foreign Key: Direct ID references (user_id → User)
  • Embedded: Nested message types within other messages
  • One-to-Many: Repeated field relationships
  • Composition: Ownership relationships between entities

RAG-Driven Data Synthesis

RAG (Retrieval-Augmented Generation) enables context-aware data generation using domain knowledge from documentation, examples, and business rules.

Configuration

grpc:
  data_synthesis:
    rag:
      enabled: true
      api_endpoint: "https://api.openai.com/v1/chat/completions"
      model: "gpt-3.5-turbo" 
      embedding_model: "text-embedding-ada-002"
      similarity_threshold: 0.7
      max_documents: 5
    context_sources:
      - id: "user_docs"
        type: "documentation"
        path: "./docs/user_guide.md"
        weight: 1.0
      - id: "examples"
        type: "examples"
        path: "./examples/sample_data.json" 
        weight: 0.8

Business Rule Extraction

The RAG system automatically extracts business rules from your documentation:

  • Email Validation: “Email fields must follow valid email format”
  • Phone Formatting: “Phone numbers should be in international format”
  • ID Requirements: “User IDs must be alphanumeric and 8 characters long”
  • Relationship Constraints: “Orders must reference valid existing users”

Domain-Aware Generation

Instead of generic random data, RAG generates contextually appropriate values:

message User {
  string role = 1; // Context: "admin", "user", "moderator" 
  string department = 2; // Context: "engineering", "marketing", "sales"
  string location = 3; // Context: "San Francisco", "New York", "London"
}

Cross-Endpoint Validation

The validation framework ensures data coherence across different endpoints and validates referential integrity.

Validation Rules

The framework supports multiple types of validation rules:

Built-in Validations:

  • Foreign key existence validation
  • Field format validation (email, phone, URL)
  • Range validation for numeric fields
  • Unique constraint validation

Custom Validation Rules:

grpc:
  data_synthesis:
    validation:
      enabled: true
      strict_mode: false
      custom_rules:
        - name: "email_format"
          applies_to: ["User", "Customer"]
          fields: ["email"]
          type: "format"
          pattern: "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
          error: "Invalid email format"
        - name: "age_range" 
          applies_to: ["User"]
          fields: ["age"]
          type: "range"
          min: 0
          max: 120
          error: "Age must be between 0 and 120"

Referential Integrity

The validator automatically checks that:

  • Foreign key references point to existing entities
  • Required relationships are satisfied
  • Cross-service data dependencies are maintained
  • Business constraints are enforced

Configuration

Environment Variables

Data synthesis is YAML-only (configured under grpc.data_synthesis.*). The cross-cutting RAG knobs that DO have env vars:

MOCKFORGE_RAG_ENABLED=true
MOCKFORGE_RAG_API_KEY=your-api-key
MOCKFORGE_RAG_MODEL=gpt-3.5-turbo

For deterministic generation, set the seed in the YAML config rather than via env var:

Configuration File

grpc:
  port: 50051
  proto_dir: "proto/"
  data_synthesis:
    enabled: true
    smart_generator:
      field_inference: true
      use_faker: true
      deterministic: true
      seed: 42
      max_depth: 5
    rag:
      enabled: true
      api_endpoint: "https://api.openai.com/v1/chat/completions"
      api_key: "${RAG_API_KEY}"
      model: "gpt-3.5-turbo"
      embedding_model: "text-embedding-ada-002"  
      similarity_threshold: 0.7
      max_context_length: 2000
      cache_contexts: true
    validation:
      enabled: true
      strict_mode: false
      max_validation_depth: 3
      cache_results: true
    schema_extraction:
      extract_relationships: true
      detect_foreign_keys: true
      confidence_threshold: 0.8

Example Usage

Basic Smart Generation

Configure data synthesis in mockforge.yaml:

grpc:
  port: 50051
  data_synthesis:
    enabled: true
    deterministic: true
    seed: 12345

Then start the server normally:

mockforge serve --config mockforge.yaml

With RAG Enhancement

MOCKFORGE_RAG_ENABLED=true \
MOCKFORGE_RAG_API_KEY=your-api-key \
mockforge serve --config mockforge.yaml --grpc-port 50051

Testing Deterministic Generation

# Generate data twice with same seed - should be identical
grpcurl -plaintext -d '{"user_id": "123"}' \
  localhost:50051 com.example.UserService/GetUser

# Reset and call again - will generate same response
grpcurl -plaintext -d '{"user_id": "123"}' \
  localhost:50051 com.example.UserService/GetUser

Best Practices

Deterministic Testing

  • Use fixed seeds in CI/CD pipelines for reproducible tests
  • Reset generators between test cases for consistency
  • Document seed values used in critical test scenarios

Schema Design for Synthesis

  • Use consistent naming conventions for foreign keys (user_id, customer_ref)
  • Add comments to proto files describing business rules
  • Consider field naming that indicates data type (email_address vs contact)

RAG Integration

  • Provide high-quality domain documentation as context sources
  • Use specific, actionable descriptions in documentation
  • Monitor API costs and implement appropriate caching

Validation Strategy

  • Start with lenient validation and gradually add stricter rules
  • Use warnings for potential issues, errors for critical problems
  • Provide helpful error messages with suggested fixes

Advanced Scenarios

Multi-Service Data Coherence

When mocking multiple related gRPC services, ensure data coherence:

# `mockforge serve` loads .proto files from ./proto in the working directory,
# so run each service from its own directory (use the same seed in each config)

# Start user service
(cd user-service && mockforge serve --grpc-port 50051) &

# Start order service
(cd order-service && mockforge serve --grpc-port 50052) &

Custom Field Overrides

Override specific fields with custom values:

grpc:
  data_synthesis:
    field_overrides:
      "admin_email": "[email protected]"
      "api_version": "v2.1"
      "environment": "testing"

Business Rule Templates

Define reusable business rule templates:

grpc:
  data_synthesis:
    rule_templates:
      - name: "financial_data"
        applies_to: ["Invoice", "Payment", "Transaction"]
        rules:
          - field_pattern: "*_amount"
            type: "range" 
            min: 0.01
            max: 10000.00
          - field_pattern: "*_currency"
            type: "enum"
            values: ["USD", "EUR", "GBP"]

Troubleshooting

Common Issues

Generated data not realistic enough

  • Enable RAG synthesis with domain documentation
  • Check field naming conventions for better inference
  • Add custom business rules for specific constraints

Non-deterministic behavior

  • Ensure deterministic: true and provide a seed value
  • Reset generators between test runs
  • Check for external randomness sources

Validation failures

  • Review foreign key naming conventions
  • Ensure referenced entities are generated before referencing ones
  • Check custom validation rule patterns

RAG not working

  • Verify API credentials and endpoints
  • Check context source file paths and permissions
  • Monitor API rate limits and error responses

Debug Commands

# Validate the configuration file
mockforge config validate --config mockforge.yaml --warnings

# Run the gRPC server with debug logging
mockforge serve --grpc-port 50051 --log-level debug

Advanced data synthesis transforms MockForge from a simple mocking tool into a comprehensive test data management platform, enabling realistic, consistent, and validated test scenarios across your entire service architecture.

Kafka Mocking

MockForge ships a wire-compatible Kafka mock broker so your producer and consumer code can run against a fake broker that speaks the real Kafka protocol — no JVM, no testcontainers, no real Kafka deployment. The mock is good for the cases where you want to know whether your client config works, whether your consumer handles the messages it gets, and whether your retry policies engage. It is not a substitute for performance testing or for verifying log compaction / replica mechanics.

Overview

The Kafka mock implements:

  • Produce / Fetch — full request/response with batches, keys, headers, and offsets
  • Metadata — broker discovery, leader assignment, advertised host override for hosted deployments
  • Group coordination — FindCoordinator, JoinGroup, SyncGroup, Heartbeat, offset commit/fetch
  • CreateTopics / DeleteTopics / DescribeConfigs — dynamic topic management
  • API version negotiation — so modern clients auto-negotiate to a supported version

What it doesn’t implement:

  • Log compaction or retention enforcement (records stay in memory for the broker’s lifetime)
  • Inter-broker replication (the mock is a single broker advertising itself as leader of every partition)
  • Realistic performance characteristics — don’t use it for benchmarks

Quick Start

Bring up a Kafka listener with topic auto-creation enabled. Your tests produce or consume topics on demand without pre-declaring them:

# mockforge.yaml
kafka:
  enabled: true
  port: 9092
  auto_create_topics: true
  default_partitions: 3
  default_replication_factor: 1
$ mockforge serve --config mockforge.yaml
[kafka] Listening on 0.0.0.0:9092 (auto_create_topics: true)

Or run the broker by itself with the dedicated CLI:

$ mockforge kafka serve --port 9092

Pointing a Client at the Broker

Use whatever Kafka client your project already has. The mock advertises localhost:9092 (or your configured advertised_host/port) through its metadata response so the client doesn’t notice it’s not a real broker.

Python (confluent-kafka)

from confluent_kafka import Producer

p = Producer({"bootstrap.servers": "localhost:9092"})
p.produce("orders.created", key="order-001", value='{"order_id":"order-001"}')
p.flush()

Go (sarama)

config := sarama.NewConfig()
config.Producer.Return.Successes = true
producer, _ := sarama.NewSyncProducer([]string{"localhost:9092"}, config)
producer.SendMessage(&sarama.ProducerMessage{
    Topic: "orders.created",
    Key:   sarama.StringEncoder("order-001"),
    Value: sarama.StringEncoder(`{"order_id":"order-001"}`),
})

Java (kafka-clients)

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String,String> p = new KafkaProducer<>(props);
p.send(new ProducerRecord<>("orders.created", "order-001", "{\"order_id\":\"order-001\"}"));
p.flush();

Seeding Messages at Startup

For tests that need messages already in the topic before the consumer runs, declare seed messages in config. The broker injects them into the topic log before accepting any client connections:

kafka:
  enabled: true
  port: 9092
  default_partitions: 3
  seed_messages:
    orders.created:
      - key: "order-001"
        value: '{"order_id":"order-001","total":4299}'
      - key: "order-002"
        value: '{"order_id":"order-002","total":1599}'
        headers:
          source: "seed"
    orders.shipped:
      - key: "order-001"
        value: '{"order_id":"order-001","carrier":"UPS"}'

Seeded records land at offset 0+, so a consumer reading from the beginning of the topic sees them immediately. Partition assignment uses Kafka’s hash-on-key strategy, so seeded records with the same key always land on the same partition (the same way real produced records would).

Fault Injection

The reason to use a mock broker over a real one for tests isn’t speed — it’s that you can deterministically reproduce specific failure modes that are nearly impossible to reproduce on a real cluster. MockForge supports three fault kinds today:

kafka:
  enabled: true
  port: 9092
  faults:
    # Sleep 2s before processing produce; exercises client retry/backoff
    - topic: orders.created
      partition: 1
      kind: produce_throttle
      delay_ms: 2000

    # 5% of fetches on this topic return OFFSET_OUT_OF_RANGE; consumer
    # hits its auto.offset.reset policy
    - topic: orders.shipped
      kind: offset_out_of_range
      probability: 0.05

    # Every produce returns NOT_LEADER_OR_FOLLOWER; client re-fetches
    # metadata and retries
    - topic: critical-pipeline
      kind: produce_not_leader
KindBehaviorKafka error code
produce_throttleSleeps delay_ms before processing the produce. Client’s request timeout / retry path engages.n/a (succeeds after delay)
produce_not_leaderReturns NOT_LEADER_OR_FOLLOWER.6
offset_out_of_rangeReturns OFFSET_OUT_OF_RANGE on fetch, regardless of actual offset.1

Match rules

  • topic is required and matched exactly
  • partition is optional; omit to target every partition of the topic
  • kind selects which request type the rule applies to
  • probability is in 0.0..=1.0; None or 1.0 means the rule fires every time (deterministic, test-friendly), 0.0 means never. When set to an intermediate value, each request rolls rand::random::<f64>() to decide
  • Rules are evaluated in declaration order; the first one that matches a given (topic, partition, kind) wins

When to reach for each kind

Test goalFault to use
Does my producer correctly back off and retry under throttling?produce_throttle
Does my consumer reset offsets the way I expect?offset_out_of_range
Does my producer recover from a leader election?produce_not_leader

CI Patterns

GitHub Actions snippet. Background the mock, wait for the port, run the tests:

- run: cargo install mockforge-cli
- name: Start mock Kafka
  run: |
    mockforge serve --config mockforge.yaml &
    timeout 30 bash -c 'until nc -z localhost 9092; do sleep 0.5; done'
- run: pytest tests/integration/

The wait-on-port loop is important: starting Kafka clients before the broker’s TCP listener is up gives confusing “broker not available” errors that look like real bugs.

Configuration Reference

All fields are documented in the Configuration page. The most commonly tweaked:

FieldDefaultNotes
enabledfalseSet to true (or pass --kafka-port on the CLI) to enable
port9092Standard Kafka port
auto_create_topicstrueWhen true, produce to a previously unknown topic creates it on demand
default_partitions3Used for auto-created topics
default_replication_factor1Advertised in metadata; the mock is a single broker
advertised_hostNoneOverride the host returned in metadata responses (useful for hosted deployments)
seed_messages{}Topic → list of records to inject at startup
faults[]List of fault-injection rules

When This Isn’t Enough

Wire-compatible mocks don’t replicate the actual log mechanics — log compaction, replica leadership transitions, performance under load. If your test depends on those, you want a real broker via testcontainers and you’re going to pay the startup tax.

For the “does my producer config work, does my consumer handle bad data, do my retry policies engage” class of tests — which is most of them — a wire-compatible mock turns a flaky 30-second CI step into a reliable one-second one.

Further Reading

GraphQL Mocking

MockForge provides GraphQL API mocking capabilities — schema-driven response generation, introspection support, custom resolvers, and a built-in Playground.

Status legend used in this chapter:

  • Implemented (default) — sections describing schema, introspection, playground, custom resolvers, automatic response generation, basic error responses, and the upstream-passthrough config field.
  • Draft / aspirational — sections describing GraphQL subscriptions, schema stitching, query-complexity caps, dedicated GraphQL caching, and graphql.performance.* config blocks. The example YAML for these isn’t wired into the current GraphQLConfig struct; treat them as roadmap. For cross-cutting concerns (latency, fault injection, rate limiting, response truncation), use the chaos engine — it covers every protocol on the same listener.

The configuration reference under “Configuration” below lists exactly what GraphQLConfig accepts today.

Overview

MockForge’s GraphQL support includes:

  • Schema-Driven Mocking: Generate responses based on GraphQL schema definitions
  • Introspection Support: Full GraphQL introspection query support
  • Custom Resolvers: Implement custom logic for specific fields via the handlers_dir config
  • Upstream Passthrough: Optionally proxy queries to a real GraphQL server (upstream_url)
  • Built-in Playground: GraphQL Playground served at the same /graphql endpoint

Getting Started

Basic Setup

Enable GraphQL mocking in your MockForge configuration:

# config.yaml
graphql:
  enabled: true
  endpoint: "/graphql"
  schema_file: "schema.graphql"
  introspection: true
  playground: true
  
server:
  http_port: 3000

Start MockForge with GraphQL support:

mockforge serve --config config.yaml

Access your GraphQL endpoint:

  • GraphQL Endpoint: http://localhost:3000/graphql
  • GraphQL Playground: http://localhost:3000/graphql/playground

Schema Definition

Create a GraphQL schema file:

# schema.graphql
type User {
  id: ID!
  name: String!
  email: String!
  age: Int
  posts: [Post!]!
  profile: UserProfile
}

type Post {
  id: ID!
  title: String!
  content: String!
  published: Boolean!
  author: User!
  createdAt: String!
  tags: [String!]!
}

type UserProfile {
  bio: String
  website: String
  location: String
  avatarUrl: String
}

type Query {
  users: [User!]!
  user(id: ID!): User
  posts: [Post!]!
  post(id: ID!): Post
  searchUsers(query: String!): [User!]!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
  createPost(input: CreatePostInput!): Post!
}

type Subscription {
  userCreated: User!
  postPublished: Post!
  userOnline(userId: ID!): Boolean!
}

input CreateUserInput {
  name: String!
  email: String!
  age: Int
}

input UpdateUserInput {
  name: String
  email: String
  age: Int
}

input CreatePostInput {
  title: String!
  content: String!
  authorId: ID!
  tags: [String!]
}

Configuration

The full set of YAML config knobs the GraphQL server reads:

graphql:
  enabled: true                  # Start the GraphQL server
  port: 4000                     # Listener port
  host: "0.0.0.0"                # Bind address
  schema_path: "schema.graphql"  # Path to .graphql / .gql schema file
  handlers_dir: "./resolvers"    # Optional directory of custom resolvers
  playground_enabled: true       # Serve GraphQL Playground at /graphql
  introspection_enabled: true    # Allow introspection queries
  upstream_url: null             # Optional: passthrough to a real GraphQL server

The endpoint path is fixed at /graphql (and Playground is served at the same path when playground_enabled is true; GET → Playground UI, POST → GraphQL execution).

CLI flags

mockforge serve --spec api.yaml \
  --graphql-port 4000 \
  --graphql              # turn on the server even if config has it disabled

For features that aren’t yet first-class GraphQL config (latency injection, fault injection, rate limiting, query-complexity caps, response caching), use the chaos engine — it covers every protocol on the same listener config surface, so a latency.fixed_delay_ms: 100 under observability.chaos adds 100 ms to every GraphQL response just as it does to HTTP and gRPC.

Response Generation

Automatic Response Generation

MockForge automatically generates realistic responses based on your schema:

# Query
query GetUsers {
  users {
    id
    name
    email
    age
    posts {
      title
      published
    }
  }
}
{
  "data": {
    "users": [
      {
        "id": "1a2b3c4d",
        "name": "Alice Johnson",
        "email": "[email protected]",
        "age": 29,
        "posts": [
          {
            "title": "Getting Started with GraphQL",
            "published": true
          },
          {
            "title": "Advanced Query Techniques",
            "published": false
          }
        ]
      },
      {
        "id": "2b3c4d5e",
        "name": "Bob Smith",
        "email": "[email protected]",
        "age": 34,
        "posts": [
          {
            "title": "Building Scalable APIs",
            "published": true
          }
        ]
      }
    ]
  }
}

Template-Based Responses

Use templates for more control over response data:

# graphql/responses/user.yaml
query: "query GetUser($id: ID!)"
response:
  data:
    user:
      id: "{{args.id}}"
      name: "{{faker.name.fullName}}"
      email: "{{faker.internet.email}}"
      age: "{{randInt 18 65}}"
      profile:
        bio: "{{faker.lorem.sentence}}"
        website: "{{faker.internet.url}}"
        location: "{{faker.address.city}}, {{faker.address.state}}"
        avatarUrl: "https://api.dicebear.com/7.x/avataaars/svg?seed={{uuid}}"

Custom Field Resolvers

Create custom resolvers for specific fields:

// graphql/resolvers/user.js
module.exports = {
  User: {
    // Custom resolver for posts field
    posts: (parent, args, context) => {
      return context.dataSources.posts.getByAuthorId(parent.id);
    },
    
    // Computed field
    fullName: (parent) => {
      return `${parent.firstName} ${parent.lastName}`;
    },
    
    // Async resolver with external data
    socialStats: async (parent, args, context) => {
      return await context.dataSources.social.getStats(parent.id);
    }
  },
  
  Query: {
    // Custom query resolver
    searchUsers: (parent, args, context) => {
      const { query, limit = 10 } = args;
      return context.dataSources.users.search(query, limit);
    }
  },
  
  Mutation: {
    // Custom mutation resolver
    createUser: (parent, args, context) => {
      const { input } = args;
      const user = {
        id: uuid(),
        ...input,
        createdAt: new Date().toISOString()
      };
      
      context.dataSources.users.create(user);
      
      // Trigger subscription
      context.pubsub.publish('USER_CREATED', { userCreated: user });
      
      return user;
    }
  }
};

Data Sources

CSV Data Source

Connect GraphQL resolvers to CSV data:

# config.yaml
graphql:
  data_sources:
    users:
      type: "csv"
      file: "data/users.csv"
      key_field: "id"
    
    posts:
      type: "csv"
      file: "data/posts.csv"
      key_field: "id"
      relationships:
        author_id: "users.id"
# data/users.csv
id,name,email,age
1,Alice Johnson,[email protected],29
2,Bob Smith,[email protected],34
3,Carol Davis,[email protected],27

REST API Data Source

Fetch data from external REST APIs:

graphql:
  data_sources:
    users:
      type: "rest"
      base_url: "https://jsonplaceholder.typicode.com"
      endpoints:
        getAll: "/users"
        getById: "/users/{id}"
        create: 
          method: "POST"
          url: "/users"
    
    posts:
      type: "rest"
      base_url: "https://jsonplaceholder.typicode.com"
      endpoints:
        getAll: "/posts"
        getByUserId: "/posts?userId={userId}"

Database Data Source

Connect to databases for realistic data:

graphql:
  data_sources:
    database:
      type: "postgresql"
      connection_string: "postgresql://user:pass@localhost/mockdb"
      tables:
        users:
          table: "users"
          key_field: "id"
        posts:
          table: "posts"
          key_field: "id"
          relationships:
            author_id: "users.id"

Subscriptions

WebSocket Subscriptions

Enable real-time GraphQL subscriptions:

graphql:
  subscriptions:
    enabled: true
    transport: "websocket"
    endpoint: "/graphql/ws"
    heartbeat_interval: 30
    connection_timeout: 60

Subscription Resolvers

// graphql/resolvers/subscriptions.js
module.exports = {
  Subscription: {
    userCreated: {
      subscribe: (parent, args, context) => {
        return context.pubsub.asyncIterator('USER_CREATED');
      }
    },
    
    postPublished: {
      subscribe: (parent, args, context) => {
        return context.pubsub.asyncIterator('POST_PUBLISHED');
      }
    },
    
    userOnline: {
      subscribe: (parent, args, context) => {
        const { userId } = args;
        return context.pubsub.asyncIterator(`USER_ONLINE_${userId}`);
      }
    }
  }
};

Triggering Subscriptions

Trigger subscriptions from mutations or external events:

// In mutation resolver
createPost: (parent, args, context) => {
  const post = createNewPost(args.input);
  
  // Trigger subscription
  context.pubsub.publish('POST_PUBLISHED', { 
    postPublished: post 
  });
  
  return post;
}

Schema Stitching

Combine multiple GraphQL schemas:

graphql:
  schema_stitching:
    enabled: true
    schemas:
      - name: "users"
        file: "schemas/users.graphql"
        endpoint: "http://users-service/graphql"
      
      - name: "posts"
        file: "schemas/posts.graphql"
        endpoint: "http://posts-service/graphql"
      
      - name: "comments"
        file: "schemas/comments.graphql"
        endpoint: "http://comments-service/graphql"
    
    # Type extensions for stitching
    extensions:
      - |
        extend type User {
          posts: [Post]
        }
      - |
        extend type Post {
          comments: [Comment]
        }

Error Handling

Custom Error Responses

Configure custom error handling:

graphql:
  errors:
    # Include detailed error information
    include_stack_trace: true
    include_extensions: true
    
    # Custom error codes
    custom_error_codes:
      INVALID_INPUT: 400
      UNAUTHORIZED: 401
      FORBIDDEN: 403
      NOT_FOUND: 404
      RATE_LIMITED: 429

Error Response Format

{
  "errors": [
    {
      "message": "User not found",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": ["user"],
      "extensions": {
        "code": "NOT_FOUND",
        "userId": "invalid-id",
        "timestamp": "2024-01-01T00:00:00Z"
      }
    }
  ],
  "data": {
    "user": null
  }
}

Performance & Optimization

Query Complexity Analysis

Prevent expensive queries:

graphql:
  performance:
    enable_query_complexity_analysis: true
    max_query_depth: 10
    max_query_complexity: 1000
    complexity_scalarCost: 1
    complexity_objectCost: 2
    complexity_listFactor: 10
    complexity_introspectionCost: 100

Caching

Cache responses for improved performance:

graphql:
  caching:
    enabled: true
    ttl_seconds: 300
    max_cache_size: 1000
    cache_key_strategy: "query_and_variables"
    
    # Cache per resolver
    resolver_cache:
      "Query.users": 600  # Cache for 10 minutes
      "Query.posts": 300  # Cache for 5 minutes

Latency Simulation

Simulate real-world latency:

graphql:
  latency:
    enabled: true
    default_delay_ms: 100
    
    # Per-field latency
    field_delays:
      "Query.users": 200
      "User.posts": 150
      "Post.comments": 100
    
    # Random latency ranges
    random_delay:
      min_ms: 50
      max_ms: 500

Testing & Development

GraphQL Playground

The built-in GraphQL Playground provides:

  • Interactive Query Editor: Write and test GraphQL queries
  • Schema Documentation: Browse your schema structure
  • Query Variables: Test with different variable values
  • Response Headers: View response metadata
  • Subscription Testing: Test real-time subscriptions

Query Examples

Test your GraphQL API with these examples:

# Simple query
query GetAllUsers {
  users {
    id
    name
    email
  }
}

# Query with variables
query GetUser($userId: ID!) {
  user(id: $userId) {
    id
    name
    email
    posts {
      title
      published
    }
  }
}

# Mutation
mutation CreateUser($input: CreateUserInput!) {
  createUser(input: $input) {
    id
    name
    email
  }
}

# Subscription
subscription UserUpdates {
  userCreated {
    id
    name
    email
  }
}

Integration with HTTP Mocking

Combine GraphQL with REST API mocking:

# config.yaml
http:
  enabled: true
  spec: "openapi.yaml"

graphql:
  enabled: true
  schema_file: "schema.graphql"
  
# Use REST endpoints in GraphQL resolvers
graphql:
  data_sources:
    rest_api:
      type: "rest"
      base_url: "http://localhost:3000"  # MockForge HTTP server
      endpoints:
        users: "/api/users"
        posts: "/api/posts"

Best Practices

Schema Design

  1. Use Descriptive Names: Choose clear, self-documenting field names
  2. Follow Conventions: Use camelCase for fields, PascalCase for types
  3. Document Your Schema: Add descriptions to types and fields
  4. Version Carefully: Use field deprecation instead of breaking changes

Performance

  1. Implement Caching: Cache expensive resolver operations
  2. Limit Query Depth: Prevent deeply nested queries
  3. Use DataLoaders: Batch and cache data fetching
  4. Monitor Complexity: Track query complexity metrics

Testing

  1. Test Query Variations: Test different query structures and variables
  2. Validate Error Cases: Ensure proper error handling
  3. Test Subscriptions: Verify real-time functionality
  4. Performance Testing: Test with realistic query loads

Troubleshooting

Common Issues

Schema Loading Errors

# There is no `mockforge graphql` subcommand. Load the schema with debug
# logging; parse errors are reported at startup
RUST_LOG=mockforge_graphql=debug mockforge serve --graphql schema.graphql --graphql-port 4000

# Check schema syntax with a third-party linter
graphql-schema-linter schema.graphql

Resolver Errors

# Enable debug logging, then send the failing query and read the resolver logs
RUST_LOG=mockforge_graphql=debug mockforge serve --graphql schema.graphql --graphql-port 4000

Subscription Issues

# Test WebSocket connection
wscat -c ws://localhost:3000/graphql/ws

This comprehensive GraphQL support makes MockForge a powerful tool for mocking modern GraphQL APIs with realistic data and behavior.

WebSocket Mocking

MockForge provides comprehensive WebSocket connection mocking with support for both scripted replay scenarios and interactive real-time communication. This enables testing of WebSocket-based applications, real-time APIs, and event-driven systems.

WebSocket Mocking Modes

MockForge supports two primary WebSocket mocking approaches:

1. Replay Mode (Scripted)

Pre-recorded message sequences that play back on schedule, simulating server behavior with precise timing control.

2. Interactive Mode (Real-time)

Dynamic responses based on client messages, enabling complex interactive scenarios and stateful communication.

Configuration

Basic WebSocket Setup

# Start MockForge with WebSocket support
mockforge serve --ws-port 3001 --ws-replay-file ws-scenario.jsonl

Environment Variables

# WebSocket configuration
MOCKFORGE_WS_PORT=3001                       # WebSocket server port
MOCKFORGE_WS_HOST=0.0.0.0                    # Bind address
MOCKFORGE_WS_REPLAY_FILE=path/to/file.jsonl  # Path to replay file
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true      # Enable template processing

The endpoint path is fixed at /ws (and /ws/{*path} for routed servers).

Command Line Options

mockforge serve \
  --ws-port 3001 \
  --ws-replay-file examples/ws-demo.jsonl

Replay Mode

Replay mode uses JSONL-formatted files to define scripted message sequences with precise timing control.

Replay File Format

Each line in the replay file is a JSON object with the following structure:

{
  "ts": 0,
  "dir": "out",
  "text": "Hello, client!",
  "waitFor": "^CLIENT_READY$"
}

Field Definitions

  • ts (number, required): Timestamp offset in milliseconds from connection start
  • dir (string, required): Message direction
    • "out" - Message sent from server to client
    • "in" - Expected message from client (for validation)
  • text (string, required): Message content (supports templates)
  • waitFor (string, optional): Regular expression to wait for before proceeding

Basic Replay Example

{"ts":0,"dir":"out","text":"Welcome to MockForge WebSocket server","waitFor":"^HELLO$"}
{"ts":1000,"dir":"out","text":"Connection established"}
{"ts":2000,"dir":"out","text":"Sending data: 42"}
{"ts":3000,"dir":"out","text":"Goodbye"}

Advanced Replay Features

Template Support

{"ts":0,"dir":"out","text":"Session {{uuid}} started at {{now}}"}
{"ts":1000,"dir":"out","text":"Random value: {{randInt 1 100}}"}
{"ts":2000,"dir":"out","text":"Future event at {{now+5m}}"}

Interactive Elements

{"ts":0,"dir":"out","text":"Please authenticate","waitFor":"^AUTH .+$"}
{"ts":100,"dir":"out","text":"Authentication successful"}
{"ts":200,"dir":"out","text":"Choose option (A/B/C)","waitFor":"^(A|B|C)$"}

Complex Message Structures

{"ts":0,"dir":"out","text":"{\"type\":\"welcome\",\"user\":{\"id\":\"{{uuid}}\",\"name\":\"John\"}}"}
{"ts":1000,"dir":"out","text":"{\"type\":\"data\",\"payload\":{\"items\":[{\"id\":1,\"value\":\"{{randInt 10 99}}\"},{\"id\":2,\"value\":\"{{randInt 100 999}}\"}]}}"}

Replay File Management

Creating Replay Files

# Record from live WebSocket connection
# (Feature in development - manual creation for now)

# Create from application logs
# Extract WebSocket messages and convert to JSONL format

# Generate programmatically
node -e "
const fs = require('fs');
const messages = [
  {ts: 0, dir: 'out', text: 'HELLO', waitFor: '^HI$'},
  {ts: 1000, dir: 'out', text: 'DATA: 42'}
];
fs.writeFileSync('replay.jsonl', messages.map(JSON.stringify).join('\n'));
"

Validation

# Validate replay file syntax
node -e "
const fs = require('fs');
const lines = fs.readFileSync('replay.jsonl', 'utf8').split('\n');
lines.forEach((line, i) => {
  if (line.trim()) {
    try {
      const msg = JSON.parse(line);
      if (!msg.ts || !msg.dir || !msg.text) {
        console.log(\`Line \${i+1}: Missing required fields\`);
      }
    } catch (e) {
      console.log(\`Line \${i+1}: Invalid JSON\`);
    }
  }
});
console.log('Validation complete');
"

Interactive Mode

Interactive mode enables dynamic responses based on client messages, supporting complex conversational patterns and state management.

Basic Interactive Setup

{"ts":0,"dir":"out","text":"What is your name?","waitFor":"^NAME .+$"}
{"ts":100,"dir":"out","text":"Hello {{request.ws.lastMessage.match(/^NAME (.+)$/)[1]}}!"}

State Management

{"ts":0,"dir":"out","text":"Welcome! Type 'START' to begin","waitFor":"^START$"}
{"ts":100,"dir":"out","text":"Game started. Score: 0","state":"playing"}
{"ts":200,"dir":"out","text":"Choose: ROCK/PAPER/SCISSORS","waitFor":"^(ROCK|PAPER|SCISSORS)$"}
{"ts":300,"dir":"out","text":"You chose {{request.ws.lastMessage}}. I chose ROCK. You win!","waitFor":"^PLAY_AGAIN$"}

Conditional Logic

{"ts":0,"dir":"out","text":"Enter command","waitFor":".+","condition":"{{request.ws.message.length > 0}}"}
{"ts":100,"dir":"out","text":"Processing: {{request.ws.message}}"}
{"ts":200,"dir":"out","text":"Command completed"}

Testing WebSocket Connections

Using WebSocket Clients

Node.js Client

const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:3001/ws');

ws.on('open', () => {
  console.log('Connected to MockForge WebSocket');
  ws.send('CLIENT_READY');
});

ws.on('message', (data) => {
  const message = data.toString();
  console.log('Received:', message);

  // Auto-respond to common prompts
  if (message.includes('ACK')) {
    ws.send('ACK');
  }
  if (message.includes('CONFIRMED')) {
    ws.send('CONFIRMED');
  }
  if (message.includes('AUTH')) {
    ws.send('AUTH token123');
  }
});

ws.on('close', () => {
  console.log('Connection closed');
});

ws.on('error', (err) => {
  console.error('WebSocket error:', err);
});

Browser JavaScript

const ws = new WebSocket('ws://localhost:3001/ws');

ws.onopen = () => {
  console.log('Connected');
  ws.send('CLIENT_READY');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
  // Handle server messages
};

ws.onclose = () => {
  console.log('Connection closed');
};

Command Line Tools

# Using websocat
websocat ws://localhost:3001/ws

# Using curl (WebSocket support experimental)
curl --include \
     --no-buffer \
     --header "Connection: Upgrade" \
     --header "Upgrade: websocket" \
     --header "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
     --header "Sec-WebSocket-Version: 13" \
     ws://localhost:3001/ws

Automated Testing

#!/bin/bash
# test-websocket.sh

echo "Testing WebSocket connection..."

# Test with Node.js
node -e "
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:3001/ws');

ws.on('open', () => {
  console.log('✓ Connection established');
  ws.send('CLIENT_READY');
});

ws.on('message', (data) => {
  console.log('✓ Message received:', data.toString());
  ws.close();
});

ws.on('close', () => {
  console.log('✓ Connection closed successfully');
  process.exit(0);
});

ws.on('error', (err) => {
  console.error('✗ WebSocket error:', err);
  process.exit(1);
});

// Timeout after 10 seconds
setTimeout(() => {
  console.error('✗ Test timeout');
  process.exit(1);
}, 10000);
"

Advanced Features

Concurrent connections

The WebSocket server accepts unlimited concurrent connections by default; each spawns its own task and runs the configured replay/interactive script independently. To rate-limit or cap connection count, use the chaos engine’s traffic_shaping.max_connections setting — it applies to all protocols (HTTP / WS / gRPC) on the same listener.

Message Filtering

{"ts":0,"dir":"in","text":".*","filter":"{{request.ws.message.startsWith('VALID_')}}"}
{"ts":100,"dir":"out","text":"Valid message received"}

Error Simulation

{"ts":0,"dir":"out","text":"Error occurred","error":"true","code":1006}
{"ts":100,"dir":"out","text":"Connection will close","close":"true"}

Binary Message Support

{"ts":0,"dir":"out","text":"AQIDBAU=","binary":"true"}
{"ts":1000,"dir":"out","text":"Binary data sent"}

Integration Patterns

Real-time Applications

  • Chat Applications: Mock user conversations and bot responses
  • Live Updates: Simulate real-time data feeds and notifications
  • Gaming: Mock multiplayer game state and player interactions

API Testing

  • WebSocket APIs: Test GraphQL subscriptions and real-time queries
  • Event Streams: Mock server-sent events and push notifications
  • Live Dashboards: Simulate real-time metrics and monitoring data

Development Workflows

  • Frontend Development: Mock WebSocket backends during UI development
  • Integration Testing: Test WebSocket handling in microservices
  • Load Testing: Simulate thousands of concurrent WebSocket connections

Best Practices

Replay File Organization

  1. Modular Files: Break complex scenarios into smaller, focused replay files
  2. Version Control: Keep replay files in Git for collaboration
  3. Documentation: Comment complex scenarios with clear descriptions
  4. Validation: Always validate replay files before deployment

Performance Considerations

  1. Message Volume: Limit concurrent connections based on system resources
  2. Memory Usage: Monitor memory usage with large replay files
  3. Timing Accuracy: Consider system clock precision for time-sensitive scenarios
  4. Connection Limits: Set appropriate connection pool sizes

Security Considerations

  1. Input Validation: Validate all client messages in interactive mode
  2. Rate Limiting: Implement connection rate limits for production
  3. Authentication: Mock authentication handshakes appropriately
  4. Data Sanitization: Avoid exposing sensitive data in replay files

Debugging Tips

  1. Verbose Logging: Enable detailed WebSocket logging for troubleshooting
  2. Connection Monitoring: Track connection lifecycle and message flow
  3. Replay Debugging: Step through replay files manually
  4. Client Compatibility: Test with multiple WebSocket client libraries

Troubleshooting

Common Issues

Connection fails: Check that WebSocket port is not blocked by firewall

Messages not received: Verify replay file path and JSONL format

Templates not expanding: Ensure MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

Timing issues: Check system clock and timestamp calculations

Debug Commands

# Check WebSocket port
netstat -tlnp | grep :3001

# Monitor connections
ss -tlnp | grep :3001

# Test basic connectivity
curl -I http://localhost:3001/health  # If HTTP health endpoint exists

Log Analysis

# View WebSocket logs
tail -f mockforge.log | grep -i websocket

# Count connections
grep "WebSocket connection" mockforge.log | wc -l

# Find errors
grep -i "websocket.*error" mockforge.log

For detailed implementation guides, see:

Replay Mode

Replay mode provides precise, scripted WebSocket message sequences that execute on a predetermined schedule. This mode is ideal for testing deterministic scenarios, reproducing specific interaction patterns, and validating client behavior against known server responses.

Core Concepts

Message Timeline

Replay files define a sequence of messages that execute based on timestamps relative to connection establishment. Each message has a precise timing offset ensuring consistent playback.

Deterministic Execution

Replay scenarios execute identically each time, making them perfect for:

  • Automated testing
  • Regression testing
  • Client behavior validation
  • Demo environments

Replay File Structure

JSONL Format

Replay files use JSON Lines format where each line contains a complete JSON object representing a single message or directive.

{"ts":0,"dir":"out","text":"Welcome message"}
{"ts":1000,"dir":"out","text":"Data update","waitFor":"^ACK$"}
{"ts":2000,"dir":"out","text":"Connection closing"}

Message Object Schema

interface ReplayMessage {
  ts: number;           // Timestamp offset in milliseconds
  dir: "out" | "in";    // Message direction
  text: string;         // Message content
  waitFor?: string;     // Optional substring to wait for in next inbound message
}

Note on waitFor: the current implementation does substring matching, not regex. "waitFor": "ready" matches any inbound message containing the literal text ready. For full regex / JSONPath matching, use the interactive mode which has richer matchers.

Note on binary frames: sending raw binary or close-frame WebSocket messages from a JSONL replay isn’t currently supported — every message is sent as a UTF-8 text frame. For binary protocols, drive traffic with a custom client (e.g. tokio-tungstenite) and use MockForge for routing only.

Basic Replay Examples

Simple Chat Simulation

{"ts":0,"dir":"out","text":"Chat server connected. Welcome!"}
{"ts":500,"dir":"out","text":"Type 'hello' to start chatting","waitFor":"^hello$"}
{"ts":100,"dir":"out","text":"Hello! How can I help you today?"}
{"ts":2000,"dir":"out","text":"Are you still there?","waitFor":".*"}
{"ts":500,"dir":"out","text":"Thanks for chatting! Goodbye."}

API Status Monitoring

{"ts":0,"dir":"out","text":"{\"type\":\"status\",\"message\":\"Monitor connected\"}"}
{"ts":1000,"dir":"out","text":"{\"type\":\"metrics\",\"cpu\":45,\"memory\":67}"}
{"ts":2000,"dir":"out","text":"{\"type\":\"metrics\",\"cpu\":42,\"memory\":68}"}
{"ts":3000,"dir":"out","text":"{\"type\":\"metrics\",\"cpu\":47,\"memory\":66}"}
{"ts":4000,"dir":"out","text":"{\"type\":\"alert\",\"level\":\"warning\",\"message\":\"High CPU usage\"}"}

Game State Synchronization

{"ts":0,"dir":"out","text":"{\"action\":\"game_start\",\"player_id\":\"{{uuid}}\",\"game_id\":\"{{uuid}}\"}"}
{"ts":1000,"dir":"out","text":"{\"action\":\"state_update\",\"position\":{\"x\":10,\"y\":20},\"score\":0}"}
{"ts":2000,"dir":"out","text":"{\"action\":\"enemy_spawn\",\"enemy_id\":\"{{uuid}}\",\"position\":{\"x\":50,\"y\":30}}"}
{"ts":1500,"dir":"out","text":"{\"action\":\"powerup\",\"type\":\"speed\",\"position\":{\"x\":25,\"y\":15}}"}
{"ts":3000,"dir":"out","text":"{\"action\":\"game_over\",\"final_score\":1250,\"reason\":\"timeout\"}"}

Advanced Replay Techniques

Conditional Branching

While replay mode is inherently linear, you can simulate branching using multiple replay files and external logic:

// File: login-success.jsonl
{"ts":0,"dir":"out","text":"Login successful","waitFor":"^ready$"}
{"ts":100,"dir":"out","text":"Welcome to your dashboard"}

// File: login-failed.jsonl
{"ts":0,"dir":"out","text":"Invalid credentials"}
{"ts":500,"dir":"out","text":"Connection will close","close":true}

Template Integration

The replay engine expands the following Handlebars-style templates inline:

TemplateWhat it expands to
{{uuid}}A new v4 UUID per message
{{now}}RFC 3339 timestamp at send time
{{now+1m}}RFC 3339 timestamp + 1 minute
{{now+1h}}RFC 3339 timestamp + 1 hour
{{randInt min max}}Random integer in [min, max] inclusive
{"ts":0,"dir":"out","text":"Session {{uuid}} established at {{now}}"}
{"ts":1000,"dir":"out","text":"Your lucky number is: {{randInt 1 100}}"}
{"ts":2000,"dir":"out","text":"Next check-in: {{now+1h}}"}

For arbitrary time offsets (e.g. +24h, +30m), pre-compute the timestamp in your test harness and inject it into the JSONL file at fixture-write time. The replay engine doesn’t currently parse arbitrary intervals. {“ts”:2000,“dir”:“out”,“text”:“Reconnection failed”,“close”:true}


## Creating Replay Files

### Manual Creation

```bash
# Create a new replay file
cat > chat-replay.jsonl << 'EOF'
{"ts":0,"dir":"out","text":"Welcome to support chat!"}
{"ts":1000,"dir":"out","text":"How can I help you today?","waitFor":".*"}
{"ts":500,"dir":"out","text":"Thanks for your question. Let me check..."}
{"ts":2000,"dir":"out","text":"I found the solution! Here's what you need to do:"}
{"ts":1000,"dir":"out","text":"1. Go to settings\n2. Click preferences\n3. Enable feature X"}
{"ts":3000,"dir":"out","text":"Does this solve your issue?","waitFor":"^(yes|no)$"}
{"ts":500,"dir":"out","text":"Great! Glad I could help. Have a nice day!"}
EOF

From Application Logs

#!/bin/bash
# extract-websocket-logs.sh

# Extract WebSocket messages from application logs
grep "WEBSOCKET_MSG" app.log | \
  # Parse log entries and convert to JSONL
  awk '{
    # Extract timestamp, direction, and message
    match($0, /([0-9]+).*dir=([^ ]*).*msg=(.*)/, arr)
    printf "{\"ts\":%d,\"dir\":\"%s\",\"text\":\"%s\"}\n", arr[1], arr[2], arr[3]
  }' > replay-from-logs.jsonl

Programmatic Generation

// generate-replay.js
const fs = require('fs');

function generateHeartbeatReplay(interval = 30000, duration = 300000) {
  const messages = [];
  const messageCount = duration / interval;

  for (let i = 0; i < messageCount; i++) {
    messages.push({
      ts: i * interval,
      dir: "out",
      text: JSON.stringify({
        type: "heartbeat",
        timestamp: `{{now+${i * interval}ms}}`,
        sequence: i + 1
      })
    });
  }

  fs.writeFileSync('heartbeat-replay.jsonl',
    messages.map(JSON.stringify).join('\n'));
}

generateHeartbeatReplay();
# generate-replay.py
import json
import random

def generate_data_stream(count=100, interval=1000):
    messages = []
    for i in range(count):
        messages.append({
            "ts": i * interval,
            "dir": "out",
            "text": json.dumps({
                "type": "data_point",
                "id": f"{{{{uuid}}}}",
                "value": random.randint(1, 100),
                "timestamp": f"{{{{now+{i * interval}ms}}}}}"
            })
        })
    return messages

# Write to file
with open('data-stream-replay.jsonl', 'w') as f:
    for msg in generate_data_stream():
        f.write(json.dumps(msg) + '\n')

Validation and Testing

Replay File Validation

# Validate JSONL syntax
node -e "
const fs = require('fs');
const lines = fs.readFileSync('replay.jsonl', 'utf8').split('\n');
let valid = true;

lines.forEach((line, i) => {
  if (line.trim()) {
    try {
      const msg = JSON.parse(line);
      if (!msg.ts || !msg.dir || !msg.text) {
        console.log(\`Line \${i+1}: Missing required fields\`);
        valid = false;
      }
      if (typeof msg.ts !== 'number' || msg.ts < 0) {
        console.log(\`Line \${i+1}: Invalid timestamp\`);
        valid = false;
      }
      if (!['in', 'out'].includes(msg.dir)) {
        console.log(\`Line \${i+1}: Invalid direction\`);
        valid = false;
      }
    } catch (e) {
      console.log(\`Line \${i+1}: Invalid JSON - \${e.message}\`);
      valid = false;
    }
  }
});

console.log(valid ? '✓ Replay file is valid' : '✗ Replay file has errors');
"

Timing Analysis

# Analyze replay timing
node -e "
const fs = require('fs');
const messages = fs.readFileSync('replay.jsonl', 'utf8')
  .split('\n')
  .filter(line => line.trim())
  .map(line => JSON.parse(line));

const timings = messages.map((msg, i) => ({
  index: i + 1,
  ts: msg.ts,
  interval: i > 0 ? msg.ts - messages[i-1].ts : 0
}));

console.log('Timing Analysis:');
timings.forEach(t => {
  console.log(\`Message \${t.index}: \${t.ts}ms (interval: \${t.interval}ms)\`);
});

const totalDuration = Math.max(...messages.map(m => m.ts));
console.log(\`Total duration: \${totalDuration}ms (\${(totalDuration/1000).toFixed(1)}s)\`);
"

Functional Testing

#!/bin/bash
# test-replay.sh

REPLAY_FILE=$1
WS_URL="ws://localhost:3001/ws"

echo "Testing replay file: $REPLAY_FILE"

# Validate file exists and is readable
if [ ! -f "$REPLAY_FILE" ]; then
  echo "✗ Replay file not found"
  exit 1
fi

# Basic syntax check
if ! node -e "
  const fs = require('fs');
  const content = fs.readFileSync('$REPLAY_FILE', 'utf8');
  const lines = content.split('\n').filter(l => l.trim());
  lines.forEach((line, i) => {
    try {
      JSON.parse(line);
    } catch (e) {
      console.error(\`Line \${i+1}: \${e.message}\`);
      process.exit(1);
    }
  });
  console.log(\`✓ Valid JSONL: \${lines.length} messages\`);
"; then
  echo "✗ Syntax validation failed"
  exit 1
fi

echo "✓ Replay file validation passed"
echo "Ready to test with: mockforge serve --ws-replay-file $REPLAY_FILE"

Best Practices

File Organization

  1. Descriptive Names: Use clear, descriptive filenames

    user-authentication-flow.jsonl
    real-time-data-stream.jsonl
    error-handling-scenarios.jsonl
    
  2. Modular Scenarios: Break complex interactions into focused files

    login-flow.jsonl
    main-interaction.jsonl
    logout-flow.jsonl
    
  3. Version Control: Keep replay files in Git with meaningful commit messages

Performance Optimization

  1. Message Batching: Group related messages with minimal intervals
  2. Memory Management: Monitor memory usage with large replay files
  3. Connection Limits: Consider concurrent connection impact

Maintenance

  1. Regular Updates: Keep replay files synchronized with application changes
  2. Documentation: Comment complex scenarios inline
  3. Versioning: Tag replay files with application versions

Debugging

  1. Verbose Logging: Enable detailed WebSocket logging during development
  2. Step-through Testing: Test replay files incrementally
  3. Timing Verification: Validate message timing against expectations

Common Patterns

Authentication Flow

{"ts":0,"dir":"out","text":"Please authenticate","waitFor":"^AUTH .+$"}
{"ts":100,"dir":"out","text":"Authenticating..."}
{"ts":500,"dir":"out","text":"Authentication successful"}
{"ts":200,"dir":"out","text":"Welcome back, user!"}

Streaming Data

{"ts":0,"dir":"out","text":"{\"type\":\"stream_start\",\"stream_id\":\"{{uuid}}\"}"}
{"ts":100,"dir":"out","text":"{\"type\":\"data\",\"value\":{{randInt 1 100}}}"}
{"ts":100,"dir":"out","text":"{\"type\":\"data\",\"value\":{{randInt 1 100}}}"}
{"ts":100,"dir":"out","text":"{\"type\":\"data\",\"value\":{{randInt 1 100}}}"}
{"ts":5000,"dir":"out","text":"{\"type\":\"stream_end\",\"total_messages\":3}"}

Error Recovery

{"ts":0,"dir":"out","text":"System operational"}
{"ts":30000,"dir":"out","text":"Warning: High load detected"}
{"ts":10000,"dir":"out","text":"Error: Service unavailable","error":true}
{"ts":5000,"dir":"out","text":"Attempting recovery..."}
{"ts":10000,"dir":"out","text":"Recovery successful"}
{"ts":1000,"dir":"out","text":"System back to normal"}

Integration with CI/CD

Automated Testing

# .github/workflows/test.yml
name: WebSocket Tests
on: [push, pull_request]

jobs:
  websocket-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install ws
      - name: Start MockForge
        run: |
          cargo install mockforge-cli
          mockforge serve --ws-replay-file examples/ws-demo.jsonl &
          sleep 2
      - name: Run WebSocket tests
        run: node test-websocket.js

Performance Benchmarking

#!/bin/bash
# benchmark-replay.sh

CONCURRENT_CONNECTIONS=100
DURATION=60

echo "Benchmarking WebSocket replay with $CONCURRENT_CONNECTIONS connections for ${DURATION}s"

# Start MockForge
mockforge serve --ws-replay-file benchmark-replay.jsonl &
SERVER_PID=$!
sleep 2

# Run benchmark
node benchmark-websocket.js $CONCURRENT_CONNECTIONS $DURATION

# Cleanup
kill $SERVER_PID

This comprehensive approach to replay mode ensures reliable, deterministic WebSocket testing scenarios that can be easily created, validated, and maintained as part of your testing infrastructure.

Interactive Mode

Interactive mode enables dynamic, real-time WebSocket communication where MockForge responds intelligently to client messages. Unlike replay mode’s predetermined sequences, interactive mode supports complex conversational patterns, state management, and adaptive responses based on client input.

Core Concepts

Dynamic Response Logic

Interactive mode evaluates client messages and generates contextually appropriate responses using conditional logic, pattern matching, and state tracking.

State Management

Connections maintain state across messages, enabling complex interactions like authentication flows, game mechanics, and multi-step processes.

Message Processing Pipeline

  1. Receive client message
  2. Parse and validate input
  3. Evaluate conditions and state
  4. Generate appropriate response
  5. Update connection state

Basic Interactive Setup

Simple Echo Server

{"ts":0,"dir":"out","text":"Echo server ready. Send me a message!"}
{"ts":0,"dir":"in","text":".*","response":"You said: {{request.ws.message}}"}

Command Processor

{"ts":0,"dir":"out","text":"Available commands: HELP, TIME, ECHO <message>, QUIT"}
{"ts":0,"dir":"in","text":"^HELP$","response":"Commands: HELP, TIME, ECHO <msg>, QUIT"}
{"ts":0,"dir":"in","text":"^TIME$","response":"Current time: {{now}}"}
{"ts":0,"dir":"in","text":"^ECHO (.+)$","response":"Echo: {{request.ws.message.match(/^ECHO (.+)$/)[1]}}"}
{"ts":0,"dir":"in","text":"^QUIT$","response":"Goodbye!","close":true}

Advanced Interactive Patterns

Authentication Flow

{"ts":0,"dir":"out","text":"Welcome! Please login with: LOGIN <username> <password>"}
{"ts":0,"dir":"in","text":"^LOGIN (\\w+) (\\w+)$","response":"Authenticating {{request.ws.message.match(/^LOGIN (\\w+) (\\w+)$/)[1]}}...","state":"authenticating"}
{"ts":1000,"dir":"out","text":"Login successful! Welcome, {{request.ws.state.username}}!","condition":"{{request.ws.state.authenticating}}"}
{"ts":0,"dir":"out","text":"Login failed. Try again.","condition":"{{!request.ws.state.authenticating}}"}

State-Based Conversations

{"ts":0,"dir":"out","text":"Welcome to the survey bot. What's your name?","state":"awaiting_name"}
{"ts":0,"dir":"in","text":".+","response":"Nice to meet you, {{request.ws.message}}! How old are you?","state":"awaiting_age","condition":"{{request.ws.state.awaiting_name}}"}
{"ts":0,"dir":"in","text":"^\\d+$","response":"Thanks! You're {{request.ws.message}} years old. Survey complete!","state":"complete","condition":"{{request.ws.state.awaiting_age}}"}
{"ts":0,"dir":"in","text":".*","response":"Please enter a valid age (numbers only).","condition":"{{request.ws.state.awaiting_age}}"}

Game Mechanics

{"ts":0,"dir":"out","text":"Welcome to Number Guessing Game! I'm thinking of a number between 1-100.","state":"playing","game":{"target":42,"attempts":0}}
{"ts":0,"dir":"in","text":"^GUESS (\\d+)$","condition":"{{request.ws.state.playing}}","response":"{{#if (eq (parseInt request.ws.message.match(/^GUESS (\\d+)$/) [1]) request.ws.state.game.target)}}You won in {{request.ws.state.game.attempts + 1}} attempts!{{else}}{{#if (gt (parseInt request.ws.message.match(/^GUESS (\\d+)$/) [1]) request.ws.state.game.target)}}Too high!{{else}}Too low!{{/if}} Try again.{{/if}}","state":"{{#if (eq (parseInt request.ws.message.match(/^GUESS (\\d+)$/) [1]) request.ws.state.game.target)}}won{{else}}playing{{/if}}","game":{"target":"{{request.ws.state.game.target}}","attempts":"{{request.ws.state.game.attempts + 1}}"}}

Message Processing Syntax

Input Patterns

Interactive mode uses regex patterns to match client messages:

// Exact match
{"dir":"in","text":"hello","response":"Hi there!"}

// Case-insensitive match
{"dir":"in","text":"(?i)hello","response":"Hi there!"}

// Pattern with capture groups
{"dir":"in","text":"^NAME (.+)$","response":"Hello, {{request.ws.message.match(/^NAME (.+)$/)[1]}}!"}

// Optional elements
{"dir":"in","text":"^(HELP|help|\\?)$","response":"Available commands: ..."}

Response Templates

Responses support the full MockForge template system:

{"dir":"in","text":".*","response":"Message received at {{now}}: {{request.ws.message}} (length: {{request.ws.message.length}})"}

Conditions

Use template conditions to control when rules apply:

{"dir":"in","text":".*","condition":"{{request.ws.state.authenticated}}","response":"Welcome back!"}
{"dir":"in","text":".*","condition":"{{!request.ws.state.authenticated}}","response":"Please authenticate first."}

State Updates

Modify connection state based on interactions:

// Set simple state
{"dir":"in","text":"START","response":"Starting...","state":"active"}

// Update complex state
{"dir":"in","text":"SCORE","response":"Current score: {{request.ws.state.score}}","state":"playing","score":"{{request.ws.state.score + 10}}"}

Advanced Features

Multi-Message Conversations

// Step 1: Greeting
{"ts":0,"dir":"out","text":"Hello! What's your favorite color?"}
{"ts":0,"dir":"in","text":".+","response":"{{request.ws.message}} is a great choice! What's your favorite food?","state":"asked_color","color":"{{request.ws.message}}","next":"food"}

// Step 2: Follow-up
{"ts":0,"dir":"out","text":"Based on your preferences, I recommend: ...","condition":"{{request.ws.state.next === 'complete'}}"}
{"ts":0,"dir":"in","text":".+","condition":"{{request.ws.state.next === 'food'}}","response":"Perfect! You like {{request.ws.state.color}} and {{request.ws.message}}. Here's a recommendation...","state":"complete"}

Error Handling

{"ts":0,"dir":"out","text":"Enter a command:"}
{"ts":0,"dir":"in","text":"","response":"Empty input not allowed. Try again."}
{"ts":0,"dir":"in","text":"^.{100,}$","response":"Input too long (max 99 characters). Please shorten."}
{"ts":0,"dir":"in","text":"^INVALID.*","response":"Unknown command. Type HELP for available commands."}
{"ts":0,"dir":"in","text":".*","response":"Processing: {{request.ws.message}}"}

Rate Limiting

{"ts":0,"dir":"in","text":".*","condition":"{{request.ws.state.messageCount < 10}}","response":"Message {{request.ws.state.messageCount + 1}}: {{request.ws.message}}","messageCount":"{{request.ws.state.messageCount + 1}}"}
{"ts":0,"dir":"in","text":".*","condition":"{{request.ws.state.messageCount >= 10}}","response":"Rate limit exceeded. Please wait."}

Session Management

// Initialize session
{"ts":0,"dir":"out","text":"Session started: {{uuid}}","sessionId":"{{uuid}}","startTime":"{{now}}","messageCount":0}

// Track activity
{"ts":0,"dir":"in","text":".*","response":"Received","messageCount":"{{request.ws.state.messageCount + 1}}","lastActivity":"{{now}}","condition":"{{request.ws.state.active}}"}

Template Functions for Interactive Mode

Message Analysis

// Message properties
{"dir":"in","text":".*","response":"Length: {{request.ws.message.length}}, Uppercase: {{request.ws.message.toUpperCase()}}"}

State Queries

// Check state existence
{"condition":"{{request.ws.state.userId}}","response":"Logged in as: {{request.ws.state.userId}}"}
{"condition":"{{!request.ws.state.userId}}","response":"Please log in first."}

// State comparisons
{"condition":"{{request.ws.state.score > 100}}","response":"High score achieved!"}
{"condition":"{{request.ws.state.level === 'expert'}}","response":"Expert mode enabled."}

Time-based Logic

// Session timeout
{"condition":"{{request.ws.state.lastActivity && (now - request.ws.state.lastActivity) > 300000}}","response":"Session expired. Please reconnect.","close":true}

// Time-based greetings
{"response":"{{#if (gte (now.getHours()) 18)}}Good evening!{{else if (gte (now.getHours()) 12)}}Good afternoon!{{else}}Good morning!{{/if}}"}

Creating Interactive Scenarios

From Scratch

# Create a new interactive scenario
cat > interactive-chat.jsonl << 'EOF'
{"ts":0,"dir":"out","text":"ChatBot: Hello! How can I help you today?"}
{"ts":0,"dir":"in","text":"(?i).*help.*","response":"ChatBot: I can answer questions, tell jokes, or just chat. What would you like?"}
{"ts":0,"dir":"in","text":"(?i).*joke.*","response":"ChatBot: Why did the computer go to the doctor? It had a virus! 😂"}
{"ts":0,"dir":"in","text":"(?i).*bye.*","response":"ChatBot: Goodbye! Have a great day! 👋","close":true}
{"ts":0,"dir":"in","text":".*","response":"ChatBot: I'm not sure how to respond to that. Try asking for help!"}
EOF

From Existing Logs

#!/bin/bash
# convert-logs-to-interactive.sh

# Extract conversation patterns from logs
grep "USER:" chat.log | sed 's/.*USER: //' | sort | uniq > user_patterns.txt
grep "BOT:" chat.log | sed 's/.*BOT: //' | sort | uniq > bot_responses.txt

# Generate interactive rules
paste user_patterns.txt bot_responses.txt | while IFS=$'\t' read -r user bot; do
  echo "{\"dir\":\"in\",\"text\":\"$(echo "$user" | sed 's/[^a-zA-Z0-9]/\\&/g')\",\"response\":\"$bot\"}"
done > interactive-from-logs.jsonl

Testing Interactive Scenarios

#!/bin/bash
# test-interactive.sh

echo "Testing interactive WebSocket scenario..."

# Start MockForge with interactive file
mockforge serve --ws-replay-file interactive-test.jsonl &
SERVER_PID=$!
sleep 2

# Test conversation flow
node -e "
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:3001/ws');

const conversation = [
  'Hello',
  'Tell me a joke',
  'What can you do?',
  'Goodbye'
];

let step = 0;

ws.on('open', () => {
  console.log('Connected, starting conversation...');
  ws.send(conversation[step++]);
});

ws.on('message', (data) => {
  const response = data.toString();
  console.log('Bot:', response);

  if (step < conversation.length) {
    setTimeout(() => {
      ws.send(conversation[step++]);
    }, 1000);
  } else {
    ws.close();
  }
});

ws.on('close', () => {
  console.log('Conversation complete');
  process.exit(0);
});

ws.on('error', (err) => {
  console.error('Error:', err);
  process.exit(1);
});
"

# Cleanup
kill $SERVER_PID

Best Practices

Design Principles

  1. Clear Conversation Flow: Design conversations with clear paths and expectations
  2. Graceful Error Handling: Provide helpful responses for unexpected input
  3. State Consistency: Keep state updates predictable and logical
  4. Performance Awareness: Avoid complex regex or template processing

Pattern Guidelines

  1. Specific to General: Order patterns from most specific to most general
  2. Anchored Regex: Use ^ and $ to avoid partial matches
  3. Case Handling: Consider case sensitivity in user input
  4. Input Validation: Validate and sanitize user input

State Management

  1. Minimal State: Store only necessary information in connection state
  2. State Validation: Verify state consistency across interactions
  3. State Cleanup: Clear state when conversations end
  4. State Persistence: Consider state requirements for reconnection scenarios

Debugging Interactive Scenarios

  1. Verbose Logging: Enable detailed WebSocket logging
  2. State Inspection: Log state changes during conversations
  3. Pattern Testing: Test regex patterns independently
  4. Flow Tracing: Track conversation paths through state changes

Common Patterns

Customer Support Chat

{"ts":0,"dir":"out","text":"Welcome to support! How can I help you? (Type your question or 'menu' for options)"}
{"ts":0,"dir":"in","text":"(?i)menu","response":"Options: 1) Password reset 2) Billing 3) Technical issue 4) Other","state":"menu"}
{"ts":0,"dir":"in","text":"(?i).*password.*","response":"I'll help you reset your password. What's your email address?","state":"password_reset","issue":"password"}
{"ts":0,"dir":"in","text":"(?i).*billing.*","response":"For billing questions, please visit our billing portal at billing.example.com","state":"billing"}
{"ts":0,"dir":"in","text":".*","response":"Thanks for your question: '{{request.ws.message}}'. A support agent will respond shortly. Your ticket ID is: {{uuid}}"}

E-commerce Assistant

{"ts":0,"dir":"out","text":"Welcome to our store! What are you looking for?","state":"browsing"}
{"ts":0,"dir":"in","text":"(?i).*shirt.*","response":"We have various shirts: casual, formal, graphic. Which style interests you?","state":"shirt_selection","category":"shirts"}
{"ts":0,"dir":"in","text":"(?i).*size.*","response":"Available sizes: S, M, L, XL. Which size would you like?","state":"size_selection","condition":"{{request.ws.state.category}}"}
{"ts":0,"dir":"in","text":"(?i)(S|M|L|XL)","condition":"{{request.ws.state.size_selection}}","response":"Great! Adding {{request.ws.state.category}} in size {{request.ws.message.toUpperCase()}} to cart. Would you like to checkout or continue shopping?","state":"checkout_ready"}

Game Server

{"ts":0,"dir":"out","text":"Welcome to the game server! Choose your character: WARRIOR, MAGE, ROGUE","state":"character_select"}
{"ts":0,"dir":"in","text":"(?i)^(warrior|mage|rogue)$","response":"Excellent choice! You selected {{request.ws.message.toUpperCase()}}. Your adventure begins now...","state":"playing","character":"{{request.ws.message.toLowerCase()}}","health":100,"level":1}
{"ts":0,"dir":"in","text":"(?i)stats","condition":"{{request.ws.state.playing}}","response":"Character: {{request.ws.state.character}}, Level: {{request.ws.state.level}}, Health: {{request.ws.state.health}}"}
{"ts":0,"dir":"in","text":"(?i)fight","condition":"{{request.ws.state.playing}}","response":"You encounter a monster! Roll for attack... {{randInt 1 20}}! {{#if (gte (randInt 1 20) 10)}}Victory!{{else}}Defeat!{{/if}}"}

Integration Examples

With Testing Frameworks

// test-interactive.js
const WebSocket = require('ws');

class InteractiveWebSocketTester {
  constructor(url) {
    this.url = url;
    this.ws = null;
  }

  async connect() {
    return new Promise((resolve, reject) => {
      this.ws = new WebSocket(this.url);
      this.ws.on('open', () => resolve());
      this.ws.on('error', reject);
    });
  }

  async sendAndExpect(message, expectedResponse) {
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => reject(new Error('Timeout')), 5000);

      this.ws.send(message);
      this.ws.once('message', (data) => {
        clearTimeout(timeout);
        const response = data.toString();
        if (response === expectedResponse) {
          resolve(response);
        } else {
          reject(new Error(`Expected "${expectedResponse}", got "${response}"`));
        }
      });
    });
  }

  close() {
    if (this.ws) this.ws.close();
  }
}

module.exports = InteractiveWebSocketTester;

Load Testing Interactive Scenarios

#!/bin/bash
# load-test-interactive.sh

CONCURRENT_USERS=50
DURATION=300

echo "Load testing interactive WebSocket with $CONCURRENT_USERS concurrent users for ${DURATION}s"

# Start MockForge
mockforge serve --ws-replay-file interactive-load-test.jsonl &
SERVER_PID=$!
sleep 2

# Run load test
node load-test-interactive.js $CONCURRENT_USERS $DURATION

# Generate report
echo "Generating performance report..."
node analyze-results.js

# Cleanup
kill $SERVER_PID

Interactive mode transforms MockForge from a simple message player into an intelligent conversation partner, enabling sophisticated testing scenarios that adapt to client behavior and maintain complex interaction state.

Plugin System

MockForge features a powerful WebAssembly-based plugin system that allows you to extend functionality without modifying the core framework. Plugins run in a secure sandbox with resource limits and provide capabilities for custom response generation, authentication, data sources, and template extensions.

Overview

The plugin system enables:

  • Custom Response Generators: Create specialized mock data and responses
  • Authentication Providers: Implement JWT, OAuth2, and custom authentication schemes
  • Data Source Connectors: Connect to CSV files, databases, and external APIs
  • Template Extensions: Add custom template functions and filters
  • Protocol Handlers: Extend support for custom protocols and formats

Plugin Architecture

WebAssembly Runtime

Plugins are compiled to WebAssembly (WASM) and run in an isolated runtime environment:

  • Security Sandbox: Isolated execution prevents plugins from accessing unauthorized resources
  • Resource Limits: CPU, memory, and execution time constraints
  • Capability System: Fine-grained permissions control what plugins can access
  • Cross-platform: WASM plugins work on any platform MockForge supports

Plugin Types

MockForge supports several plugin types:

TypeDescriptionInterface
responseGenerate custom response dataResponseGenerator
authHandle authentication and authorizationAuthProvider
datasourceConnect to external data sourcesDataSourceConnector
templateAdd custom template functionsTemplateExtension
protocolSupport custom protocolsProtocolHandler

Installing Plugins

From Plugin Registry

# Install plugin from registry
mockforge plugin install auth-jwt

# Install specific version
mockforge plugin install [email protected]

# Search the registry
mockforge plugin search auth

From Local File

# Install from local WASM file
mockforge plugin install ./my-plugin.wasm

# Install from a local plugin directory (reads plugin.yaml from the directory)
mockforge plugin install ./my-plugin/

From Git Repository

# Install from Git repository
mockforge plugin install https://github.com/example/mockforge-plugin-custom.git

# Install specific branch/tag
mockforge plugin install https://github.com/example/mockforge-plugin-custom.git#v1.0.0

Plugin Management

List Installed Plugins

# List all installed plugins
mockforge plugin list

# Show detailed information
mockforge plugin list --detailed

# Show details for one plugin
mockforge plugin info auth-jwt

Update Plugins

# Update specific plugin
mockforge plugin update auth-jwt

# Update all plugins
mockforge plugin update --all

Remove Plugins

# Remove plugin
mockforge plugin uninstall auth-jwt

Plugin Configuration

Global Configuration

Configure plugins in your MockForge configuration file:

plugins:
  enabled: true
  directory: "~/.mockforge/plugins"
  runtime:
    memory_limit_mb: 64
    cpu_limit_percent: 10
    execution_timeout_ms: 5000
  
  # Plugin-specific configuration
  auth-jwt:
    enabled: true
    config:
      secret_key: "${JWT_SECRET}"
      algorithm: "HS256"
      expiration: 3600
  
  datasource-csv:
    enabled: true
    config:
      base_directory: "./data"
      cache_ttl: 300

Environment Variables

Plugin system settings (registry URL, runtime limits, directory) are YAML-only — configure under plugins.* in mockforge.yaml. The token for publishing to the registry is the only env var:

export MOCKFORGE_REGISTRY_TOKEN=mfreg_...

# Plugin-specific settings (per-plugin auth/data, NOT MockForge core)
export JWT_SECRET=your-secret-key
export CSV_DATA_DIR=./test-data

Developing Plugins

Plugin Manifest

Every plugin requires a plugin.yaml manifest file:

# plugin.yaml
name: "auth-jwt"
version: "1.0.0"
description: "JWT authentication provider"
author: "Your Name <[email protected]>"
license: "MIT"
repository: "https://github.com/example/mockforge-plugin-auth-jwt"

# Plugin metadata
type: "auth"
category: "authentication"
tags: ["jwt", "auth", "security"]

# Runtime requirements
runtime:
  wasm_version: "0.1"
  memory_limit_mb: 32
  execution_timeout_ms: 1000

# Capabilities required
capabilities:
  - "network.http.client"
  - "storage.key_value"
  - "template.functions"

# Configuration schema
config_schema:
  type: "object"
  properties:
    secret_key:
      type: "string"
      description: "JWT signing secret"
      required: true
    algorithm:
      type: "string"
      enum: ["HS256", "HS384", "HS512", "RS256"]
      default: "HS256"
    expiration:
      type: "integer"
      description: "Token expiration in seconds"
      default: 3600
      minimum: 60

# Export information
exports:
  auth_provider: "JwtAuthProvider"
  template_functions:
    - "jwt_encode"
    - "jwt_decode"
    - "jwt_verify"

Rust Plugin Development

Create a new Rust project for your plugin:

cargo new --lib mockforge-plugin-custom
cd mockforge-plugin-custom

Add dependencies to Cargo.toml:

[package]
name = "mockforge-plugin-custom"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
mockforge-plugin-core = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
wasm-bindgen = "0.2"

[dependencies.web-sys]
version = "0.3"
features = [
  "console",
]

Implement your plugin in src/lib.rs:

#![allow(unused)]
fn main() {
use mockforge_plugin_core::{
    AuthProvider, AuthResult, PluginConfig, PluginError, PluginResult,
    export_auth_provider, export_template_functions
};
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

#[derive(Deserialize)]
struct JwtConfig {
    secret_key: String,
    algorithm: String,
    expiration: u64,
}

pub struct JwtAuthProvider {
    config: JwtConfig,
}

impl JwtAuthProvider {
    pub fn new(config: PluginConfig) -> PluginResult<Self> {
        let jwt_config: JwtConfig = serde_json::from_value(config.into())?;
        Ok(Self { config: jwt_config })
    }
}

impl AuthProvider for JwtAuthProvider {
    fn authenticate(&self, token: &str) -> PluginResult<AuthResult> {
        // Implement JWT validation logic
        match self.verify_jwt(token) {
            Ok(claims) => Ok(AuthResult::success(claims)),
            Err(e) => Ok(AuthResult::failure(e.to_string())),
        }
    }
    
    fn generate_token(&self, user_id: &str) -> PluginResult<String> {
        // Implement JWT generation logic
        self.create_jwt(user_id)
    }
}

impl JwtAuthProvider {
    fn verify_jwt(&self, token: &str) -> Result<serde_json::Value, PluginError> {
        // JWT verification implementation
        todo!("Implement JWT verification")
    }
    
    fn create_jwt(&self, user_id: &str) -> PluginResult<String> {
        // JWT creation implementation
        todo!("Implement JWT creation")
    }
}

// Template functions
#[wasm_bindgen]
pub fn jwt_encode(payload: &str, secret: &str) -> String {
    // Implement JWT encoding for templates
    todo!("Implement template JWT encoding")
}

#[wasm_bindgen]
pub fn jwt_decode(token: &str) -> String {
    // Implement JWT decoding for templates
    todo!("Implement template JWT decoding")
}

// Export plugin interfaces
export_auth_provider!(JwtAuthProvider);
export_template_functions! {
    "jwt_encode" => jwt_encode,
    "jwt_decode" => jwt_decode,
}
}

Building Plugins

Build your plugin to WebAssembly:

# Install wasm-pack if not already installed
cargo install wasm-pack

# Build the plugin
wasm-pack build --target web --out-dir pkg

# The WASM file will be in pkg/mockforge_plugin_custom.wasm

Testing Plugins

MockForge provides a testing framework for plugins:

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    use mockforge_plugin_core::test_utils::*;

    #[test]
    fn test_jwt_authentication() {
        let config = test_config! {
            "secret_key": "test-secret",
            "algorithm": "HS256",
            "expiration": 3600
        };
        
        let provider = JwtAuthProvider::new(config).unwrap();
        
        // Test valid token
        let token = provider.generate_token("user123").unwrap();
        let result = provider.authenticate(&token).unwrap();
        assert!(result.is_success());
        
        // Test invalid token
        let invalid_result = provider.authenticate("invalid.token.here").unwrap();
        assert!(invalid_result.is_failure());
    }
}
}

Plugin Examples

MockForge includes several example plugins to demonstrate different capabilities:

Authentication Plugins

Basic Authentication (auth-basic)

# examples/plugins/auth-basic/plugin.yaml
name: "auth-basic"
type: "auth"
description: "HTTP Basic Authentication provider"

config_schema:
  type: "object"
  properties:
    users:
      type: "object"
      description: "Username to password mapping"
    realm:
      type: "string"
      default: "MockForge"

Usage in MockForge configuration:

plugins:
  auth-basic:
    enabled: true
    config:
      realm: "API Access"
      users:
        admin: "password123"
        user: "userpass"

JWT Authentication (auth-jwt)

Advanced JWT authentication with support for multiple algorithms:

# examples/plugins/auth-jwt/plugin.yaml
name: "auth-jwt"
type: "auth"
description: "JWT authentication provider with multiple algorithm support"

capabilities:
  - "storage.key_value"
  - "template.functions"

config_schema:
  type: "object"
  properties:
    secret_key:
      type: "string"
      required: true
    algorithm:
      type: "string"
      enum: ["HS256", "HS384", "HS512", "RS256", "RS384", "RS512"]
      default: "HS256"
    issuer:
      type: "string"
      description: "JWT issuer claim"
    audience:
      type: "string"
      description: "JWT audience claim"

Data Source Plugins

CSV Data Source (datasource-csv)

Connect to CSV files as data sources:

# examples/plugins/datasource-csv/plugin.yaml
name: "datasource-csv"
type: "datasource"
description: "CSV file data source connector"

config_schema:
  type: "object"
  properties:
    base_directory:
      type: "string"
      description: "Base directory for CSV files"
      required: true
    cache_ttl:
      type: "integer"
      description: "Cache TTL in seconds"
      default: 300
    delimiter:
      type: "string"
      description: "CSV delimiter"
      default: ","

Usage in templates:

response:
  status: 200
  body:
    users: "{{datasource.csv('users.csv').random(5)}}"
    products: "{{datasource.csv('products.csv').filter('category', 'electronics')}}"

Template Plugins

Crypto Functions (template-crypto)

Add cryptographic template functions:

# examples/plugins/template-crypto/plugin.yaml
name: "template-crypto"
type: "template"
description: "Cryptographic template functions"

exports:
  template_functions:
    - "crypto_hash"
    - "crypto_hmac"
    - "crypto_encrypt"
    - "crypto_decrypt"
    - "crypto_random"

Template usage:

response:
  body:
    user_id: "{{uuid}}"
    password_hash: "{{crypto_hash(faker.password, 'sha256')}}"
    api_key: "{{crypto_random(32, 'hex')}}"
    signature: "{{crypto_hmac(request.body, env.API_SECRET, 'sha256')}}"

Response Plugins

GraphQL Response Generator (response-graphql)

Generate GraphQL responses from schema:

# examples/plugins/response-graphql/plugin.yaml
name: "response-graphql"
type: "response"
description: "GraphQL response generator"

config_schema:
  type: "object"
  properties:
    schema_file:
      type: "string"
      description: "Path to GraphQL schema file"
      required: true
    resolvers:
      type: "object"
      description: "Custom resolver configuration"

Security Considerations

Capability System

Plugins must declare required capabilities:

# plugin.yaml
capabilities:
  - "network.http.client"     # Make HTTP requests
  - "network.http.server"     # Handle HTTP requests
  - "storage.key_value"       # Access key-value storage
  - "storage.file.read"       # Read files
  - "storage.file.write"      # Write files
  - "template.functions"      # Register template functions
  - "crypto.random"           # Access random number generation
  - "crypto.hash"             # Access hashing functions

Resource Limits

Configure resource limits per plugin:

plugins:
  my-plugin:
    runtime:
      memory_limit_mb: 64        # Maximum memory usage
      cpu_limit_percent: 5       # Maximum CPU usage
      execution_timeout_ms: 2000 # Maximum execution time
      network_timeout_ms: 1000   # Network request timeout

Sandboxing

Plugins run in a secure sandbox that:

  • Prevents access to the host file system outside permitted directories
  • Limits network access to declared endpoints
  • Restricts system calls and resource usage
  • Isolates plugin memory from the host process

Best Practices

Plugin Development

  1. Keep plugins focused: Each plugin should have a single, clear purpose
  2. Minimize resource usage: Use efficient algorithms and limit memory allocation
  3. Handle errors gracefully: Return meaningful error messages
  4. Document configuration: Provide clear schema and examples
  5. Test thoroughly: Include comprehensive tests for all functionality

Plugin Usage

  1. Review plugin capabilities: Understand what permissions plugins require
  2. Monitor resource usage: Check plugin performance and resource consumption
  3. Keep plugins updated: Regularly update to get security fixes and improvements
  4. Use official plugins: Prefer plugins from trusted sources
  5. Test in development: Thoroughly test plugins before production use

Security

  1. Audit plugin code: Review plugin source code when possible
  2. Limit capabilities: Only grant necessary permissions
  3. Monitor logs: Watch for suspicious plugin behavior
  4. Use resource limits: Prevent plugins from consuming excessive resources
  5. Isolate environments: Use separate plugin configurations for development and production

Hook Points Reference

MockForge plugins implement one or more of seven traits, each hooked into a specific point in the request / response lifecycle. A single plugin can implement several traits to extend multiple stages.

TraitWhen it runsUse cases
TemplatePluginDuring response templatingCustom {{my.fn arg}} template functions, inline crypto / encoding helpers
AuthPluginBefore route matchingCustom JWT/OAuth validators, header-based auth schemes, request signing verification
ResponsePluginAfter route matching, before writeGenerate the response body from scratch (e.g. AI-driven, computed)
ResponseModifierPluginAfter response generationPost-process bodies (compression, redaction, watermarking, schema masking)
DataSourcePluginWhen a route requests external dataCSV / database / external-API connectors backing fixtures
BackendGeneratorPluginAt spec import timeGenerate full mock backends from non-OpenAPI specs (gRPC reflect, custom DSLs)
ClientGeneratorPluginAt spec import timeEmit client SDKs from a spec for testing

Each trait gets a PluginContext with:

  • The current request (method, path, headers, body)
  • A handle to the in-memory storage (storage.key_value capability)
  • A logger (tracing macros, scoped to the plugin name)
  • Random / time / template helpers from the host

See crates/mockforge-plugin-core/src/ for the canonical trait definitions.

Publishing to the Registry

The plugin registry at registry.mockforge.dev hosts community plugins, checksummed and optionally signed, with semver-pinnable versions. Authoring and publishing commands live in the separate mockforge-plugin binary. Publishing is a four-step flow.

1. Generate publisher keys

# One-time setup: writes the private key (PKCS#8 PEM, mode 0600) and prints the base64 public key
mockforge-plugin key gen --out mockforge_publisher_key.pem

# Register the public key with your registry account
mockforge-plugin key add --label laptop --public-key <base64-public-key>

# List the keys registered on your account
mockforge-plugin key list

Your private key signs the SBOM attestation for each release; the registry verifies it against your registered public keys. Keep the private key file readable only by your user account. Use mockforge-plugin key rotate to replace a key and mockforge-plugin key revoke <id> to retire one.

2. Authenticate to the registry

# Create an account at https://registry.mockforge.dev and copy your token
export MOCKFORGE_REGISTRY_TOKEN=mfreg_...

All mockforge-plugin key and publish commands also accept --token and --registry (or MOCKFORGE_REGISTRY_URL).

3. Prepare the manifest

# plugin.yaml in your plugin's repo root
name: "my-cool-plugin"
version: "1.0.0"          # semver, monotonically increasing per release
description: "A short, scannable summary"
author: "your-name"
license: "MIT OR Apache-2.0"
homepage: "https://github.com/you/my-cool-plugin"
repository: "https://github.com/you/my-cool-plugin"

capabilities:
  - "network.http.client"
  - "storage.key_value"

runtime:
  memory_limit_mb: 64
  cpu_limit_percent: 5
  execution_timeout_ms: 1000

# Versions of MockForge this plugin targets
mockforge:
  min_version: "0.3.125"
  max_version: "0.4.0"

# Files to include in the published bundle (relative to repo root)
include:
  - "target/wasm32-unknown-unknown/release/my_cool_plugin.wasm"
  - "plugin.yaml"
  - "README.md"
  - "LICENSE-*"

Validate before pushing (run from the plugin project directory):

mockforge-plugin validate

4. Publish

# Build the WASM module, package it as a .zip, then publish
mockforge-plugin build --release
mockforge-plugin package
mockforge-plugin publish

# Attach a signed SBOM attestation
mockforge-plugin publish --sign --key-file mockforge_publisher_key.pem --sbom sbom.json

# Validate and describe the upload without sending it
mockforge-plugin publish --dry-run

Under the hood:

  1. The .zip package produced by package is located and validated (it must contain the manifest and a .wasm module)
  2. With --sign, the SBOM is signed over SHA-256(artifact_checksum || canonical(sbom)) with your private key
  3. The package (plus SBOM and signature, if signed) is uploaded with the bearer token from --token or MOCKFORGE_REGISTRY_TOKEN
  4. The registry verifies the signature against your registered public keys

Yanking a release

If a release has a critical bug, yank it. There is no CLI command for this; call the registry API with your token:

curl -X DELETE \
  -H "Authorization: Bearer $MOCKFORGE_REGISTRY_TOKEN" \
  https://registry.mockforge.dev/api/v1/plugins/my-cool-plugin/versions/1.0.0/yank

Yanks aren’t deletions — they’re advisory. To fully remove a release for GDPR / legal reasons, contact registry operators.

Verification & Trust

When you mockforge plugin install <name>@<version>, MockForge:

  1. Resolves the version constraint against the registry
  2. Downloads the signed bundle
  3. Verifies the SHA-256 checksum matches the registry’s stored value
  4. Verifies the package signature against the publisher’s registered public key
  5. Caches the bundle locally for reproducibility

If any verification step fails, install aborts with a clear error and nothing gets unpacked.

Verifying a third-party plugin manually

# Validate a plugin without installing it
mockforge plugin validate ./suspicious-plugin/

# Install from a URL, pinning the expected SHA-256 checksum
mockforge plugin install https://example.com/plugin.zip --checksum <sha256>

Always validate plugins from unfamiliar publishers before installing.

Troubleshooting

Common Issues

Plugin Won’t Load

# Show plugin information
mockforge plugin info my-plugin

# Validate the plugin
mockforge plugin validate ./my-plugin/

# Check logs for errors
mockforge logs --json | grep -i plugin

Runtime Errors

# Enable debug logging
RUST_LOG=mockforge_plugin_loader=debug mockforge serve

Performance Issues

There is no CLI for per-plugin runtime stats or profiling. Use debug logging (above) and mockforge plugin cache-stats to inspect the plugin download cache.

This comprehensive plugin system enables powerful extensibility while maintaining security and performance. Plugins can significantly extend MockForge’s capabilities for specialized use cases and integrations.

Security & Encryption

MockForge provides enterprise-grade security features including end-to-end encryption, secure key management, and comprehensive authentication systems to protect your mock data and configurations.

Overview

MockForge’s security features include:

  • End-to-End Encryption: AES-256-GCM and ChaCha20-Poly1305 algorithms
  • Hierarchical Key Management: Master keys, workspace keys, and session keys
  • Auto-Encryption: Automatic encryption of sensitive configuration data
  • Secure Storage: OS keychain integration and file-based key storage
  • Template Encryption: Built-in encryption/decryption functions in templates
  • Role-Based Access Control: Admin and viewer roles in the UI
  • Plugin Security: Sandboxed plugin execution with capability controls

Encryption Setup

Initial Configuration

Enable encryption via the security.encryption.* block in mockforge.yaml (see Configuration File below). The encryption key is loaded via MOCKFORGE_ENCRYPTION_KEY / MOCKFORGE_MASTER_KEY / MOCKFORGE_KMS_PROVIDER (see Environment Variables).

# Start MockForge with encryption configured in YAML
MOCKFORGE_ENCRYPTION_KEY=$(cat encryption.key) \
  mockforge serve --config config.yaml

Configuration File

Configure encryption in your YAML configuration:

# config.yaml
encryption:
  enabled: true
  algorithm: "aes-256-gcm"  # or "chacha20-poly1305"
  key_store:
    type: "file"  # or "os_keychain"
    path: "~/.mockforge/keys"
    auto_create: true
  
  # Auto-encryption rules
  auto_encrypt:
    enabled: true
    patterns:
      - "*.password"
      - "*.secret"
      - "*.key"
      - "*.token"
      - "auth.headers.*"
      - "database.connection_string"
  
  # Key rotation
  rotation:
    enabled: true
    interval_days: 30
    backup_count: 5

Key Management

Key Hierarchy

MockForge uses a hierarchical key system:

  1. Master Key: Root encryption key stored securely
  2. Workspace Keys: Per-workspace encryption keys derived from master key
  3. Session Keys: Temporary keys for active sessions
  4. Data Keys: Keys for encrypting specific data elements

Key Storage Options

File-Based Storage

Store keys in encrypted files on the local filesystem:

encryption:
  key_store:
    type: "file"
    path: "~/.mockforge/keys"
    permissions: "0600"  # Owner read/write only
    backup_enabled: true
    backup_path: "~/.mockforge/keys.backup"

OS Keychain Integration

Use the operating system’s secure keychain:

encryption:
  key_store:
    type: "os_keychain"
    service_name: "mockforge"
    account_prefix: "workspace_"

Supported Platforms:

  • macOS: Uses Keychain Services
  • Windows: Uses Windows Credential Manager
  • Linux: Uses Secret Service API (GNOME Keyring, KWallet)

Key Generation

MockForge automatically generates keys when needed. There is no mockforge keys CLI for initializing, generating, rotating, or exporting keys; key management is driven by the encryption configuration shown in this guide.

Key Rotation

Implement automatic key rotation for enhanced security:

encryption:
  rotation:
    enabled: true
    interval_days: 30
    max_key_age_days: 90
    backup_old_keys: true
    notify_before_rotation_days: 7

Encryption Algorithms

AES-256-GCM (Default)

encryption:
  algorithm: "aes-256-gcm"
  config:
    key_size: 256
    iv_size: 12
    tag_size: 16

Features:

  • Performance: Optimized for speed on modern CPUs
  • Security: NIST-approved, widely audited
  • Authentication: Built-in message authentication
  • Hardware Support: AES-NI acceleration on Intel/AMD

ChaCha20-Poly1305

encryption:
  algorithm: "chacha20-poly1305"
  config:
    key_size: 256
    nonce_size: 12
    tag_size: 16

Features:

  • Performance: Excellent on ARM and older CPUs
  • Security: Modern, quantum-resistant design
  • Authentication: Integrated Poly1305 MAC
  • Simplicity: Fewer implementation pitfalls

Auto-Encryption

MockForge automatically encrypts sensitive data based on configurable patterns:

Configuration Patterns

encryption:
  auto_encrypt:
    enabled: true
    patterns:
      # Password fields
      - "*.password"
      - "*.passwd"
      - "auth.password"
      
      # API keys and tokens
      - "*.api_key"
      - "*.secret_key"
      - "*.access_token"
      - "*.refresh_token"
      
      # Database connections
      - "database.password"
      - "database.connection_string"
      - "redis.password"
      
      # HTTP headers
      - "auth.headers.Authorization"
      - "auth.headers.X-API-Key"
      
      # Custom patterns
      - "custom.sensitive_data.*"

Field-Level Encryption

Encrypt specific fields in your configurations:

# Original configuration
database:
  host: "localhost"
  port: 5432
  username: "user"
  password: "secret123"  # Will be auto-encrypted
  
auth:
  jwt_secret: "my-secret"  # Will be auto-encrypted
  
# After auto-encryption
database:
  host: "localhost"
  port: 5432
  username: "user"
  password: "{{encrypted:AES256:base64-encrypted-data}}"
  
auth:
  jwt_secret: "{{encrypted:AES256:base64-encrypted-data}}"

Template Encryption Functions

Use encryption functions directly in your templates:

Encryption Functions

# Encrypt data in templates
response:
  body:
    user_id: "{{uuid}}"
    encrypted_data: "{{encrypt('sensitive-data', 'workspace-key')}}"
    hashed_password: "{{hash('password123', 'sha256')}}"
    signed_token: "{{sign(user_data, 'signing-key')}}"

Decryption Functions

# Decrypt data in templates
request:
  headers:
    Authorization: "Bearer {{decrypt(encrypted_token, 'workspace-key')}}"
  body:
    password: "{{decrypt(user.encrypted_password, 'user-key')}}"

Available Functions

FunctionDescriptionExample
encrypt(data, key)Encrypt data with specified key{{encrypt('secret', 'my-key')}}
decrypt(data, key)Decrypt data with specified key{{decrypt(encrypted_data, 'my-key')}}
hash(data, algorithm)Hash data with algorithm{{hash('password', 'sha256')}}
hmac(data, key, algorithm)Generate HMAC signature{{hmac(message, 'secret', 'sha256')}}
sign(data, key)Sign data with private key{{sign(payload, 'private-key')}}
verify(data, signature, key)Verify signature with public key{{verify(data, sig, 'public-key')}}

Mutual TLS (mTLS)

MockForge supports Mutual TLS (mTLS) for enhanced security, requiring both server and client certificates for authentication.

Quick Start

Enable mTLS in your configuration:

http:
  tls:
    enabled: true
    cert_file: "./certs/server.crt"
    key_file: "./certs/server.key"
    ca_file: "./certs/ca.crt"           # CA certificate for client verification
    require_client_cert: true            # Enable mTLS

Client Configuration

Clients must provide a certificate signed by the CA:

# Using cURL
curl --cert client.crt --key client.key --cacert ca.crt \
  https://localhost:3000/api/endpoint

Certificate Generation

For development, use mkcert:

# Install mkcert
brew install mkcert
mkcert -install

# Generate certificates
mkcert localhost 127.0.0.1 ::1
mkcert -client localhost 127.0.0.1 ::1

For production, use OpenSSL or a trusted Certificate Authority.

Full Documentation: See mTLS Configuration Guide for complete setup instructions, certificate generation, client examples, and troubleshooting.

Authentication & Authorization

Admin UI Authentication

MockForge Admin UI v2 includes complete role-based authentication with JWT-based authentication:

admin:
  auth:
    enabled: true
    jwt_secret: "{{encrypted:your-jwt-secret}}"
    session_timeout: 86400  # 24 hours
    
    # Built-in users
    users:
      admin:
        password: "{{encrypted:admin-password}}"
        role: "admin"
      viewer:
        password: "{{encrypted:viewer-password}}"
        role: "viewer"
        
    # Custom authentication provider
    provider: "custom"
    provider_config:
      ldap_url: "ldap://company.com"
      oauth2_client_id: "mockforge-client"

Role Permissions

RolePermissions
AdminFull access to all features (workspace management, member management, all editing)
EditorCreate, edit, and delete mocks; view history; cannot manage workspace settings
ViewerRead-only access to dashboard, logs, metrics, and mocks

Full Documentation: See RBAC Guide for complete role and permission details.

Custom Authentication

Implement custom authentication via plugins:

#![allow(unused)]
fn main() {
// Custom auth plugin
use mockforge_plugin_core::{AuthProvider, AuthResult};

pub struct LdapAuthProvider {
    ldap_url: String,
    base_dn: String,
}

impl AuthProvider for LdapAuthProvider {
    fn authenticate(&self, username: &str, password: &str) -> AuthResult {
        // LDAP authentication logic
        match self.ldap_authenticate(username, password) {
            Ok(user_info) => AuthResult::success(user_info),
            Err(e) => AuthResult::failure(e.to_string()),
        }
    }
}
}

Plugin Security

Capability System

Plugins must declare required capabilities:

# plugin.yaml
capabilities:
  - "crypto.encrypt"      # Encryption functions
  - "crypto.decrypt"      # Decryption functions
  - "crypto.hash"         # Hashing functions
  - "crypto.random"       # Random number generation
  - "storage.encrypted"   # Encrypted storage access
  - "network.tls"         # TLS/SSL connections

Resource Limits

Configure security limits for plugins:

plugins:
  security:
    memory_limit_mb: 64
    cpu_limit_percent: 5
    network_timeout_ms: 5000
    file_access_paths:
      - "/app/data"
      - "/tmp/plugin-cache"
    
    # Encryption access
    encryption_access:
      allowed_algorithms: ["aes-256-gcm"]
      key_access_patterns: ["workspace.*", "plugin.*"]

Sandboxing

Plugins run in secure sandboxes that:

  • Isolate Memory: Separate memory space from host process
  • Limit File Access: Restricted to declared paths only
  • Control Network: Limited to specified endpoints
  • Monitor Resources: CPU, memory, and execution time limits
  • Audit Operations: Log all security-relevant operations

Transport Security

TLS Configuration

Enable TLS for all network communication:

# Server TLS
server:
  tls:
    enabled: true
    cert_file: "/path/to/server.crt"
    key_file: "/path/to/server.key"
    min_version: "1.3"
    cipher_suites:
      - "TLS_AES_256_GCM_SHA384"
      - "TLS_CHACHA20_POLY1305_SHA256"

# Client TLS (for outbound requests)
client:
  tls:
    verify_certificates: true
    ca_bundle: "/path/to/ca-bundle.crt"
    client_cert: "/path/to/client.crt"
    client_key: "/path/to/client.key"

Certificate Management

MockForge does not generate or import certificates itself (there is no mockforge certs command). Create certificates with your usual tooling and pass them to the server:

mockforge serve --spec api.json --https-port 3443 --tls-cert ./certs/server.crt --tls-key ./certs/server.key

# Mutual TLS with a CA bundle
mockforge serve --spec api.json --tls-enabled --tls-cert server.crt --tls-key server.key --tls-ca ca.crt --mtls required

Security Best Practices

Configuration Security

  1. Encrypt Sensitive Data: Use auto-encryption for passwords and keys
  2. Secure Key Storage: Use OS keychain in production
  3. Regular Key Rotation: Implement automatic key rotation
  4. Least Privilege: Grant minimal necessary permissions
  5. Audit Logging: Enable comprehensive security logging

Deployment Security

  1. Use TLS: Enable TLS for all network communication
  2. Network Isolation: Deploy in isolated network segments
  3. Access Control: Implement proper firewall rules
  4. Monitor Security: Set up security monitoring and alerting
  5. Regular Updates: Keep MockForge and dependencies updated

Plugin Security

  1. Review Plugin Code: Audit plugin source code before installation
  2. Limit Capabilities: Grant only necessary plugin permissions
  3. Monitor Resources: Watch plugin resource usage
  4. Isolate Environments: Use separate configs for dev/prod
  5. Update Regularly: Keep plugins updated for security fixes

Security Monitoring

Audit Logging

Enable comprehensive security logging:

logging:
  security:
    enabled: true
    level: "info"
    destinations:
      - type: "file"
        path: "/var/log/mockforge/security.log"
        format: "json"
      - type: "syslog"
        facility: "local0"
        tag: "mockforge-security"
    
    events:
      - "auth_success"
      - "auth_failure"
      - "key_access"
      - "encryption_operation"
      - "plugin_security_violation"
      - "configuration_change"

Security Metrics

Monitor security-related metrics:

metrics:
  security:
    enabled: true
    metrics:
      - "auth_attempts_total"
      - "auth_failures_total"
      - "encryption_operations_total"
      - "key_rotations_total"
      - "plugin_security_violations_total"

Alerting

Set up security alerts:

alerts:
  security:
    enabled: true
    rules:
      - name: "High Authentication Failures"
        condition: "auth_failures_rate > 10/minute"
        action: "email_admin"
      
      - name: "Plugin Security Violation"
        condition: "plugin_security_violations > 0"
        action: "disable_plugin"
      
      - name: "Encryption Key Access Anomaly"
        condition: "key_access_rate > 100/minute"
        action: "alert_security_team"

Compliance & Standards

Standards Compliance

MockForge security features comply with:

  • FIPS 140-2: Cryptographic standards compliance
  • Common Criteria: Security evaluation criteria
  • SOC 2 Type II: Security, availability, and confidentiality
  • ISO 27001: Information security management

Data Protection

Features for data protection compliance:

  • Data Encryption: All sensitive data encrypted at rest and in transit
  • Key Management: Secure key lifecycle management
  • Access Controls: Role-based access and audit trails
  • Data Minimization: Only collect and store necessary data
  • Right to Deletion: Secure data deletion capabilities

Audit Logging

MockForge provides comprehensive audit logging for security and compliance:

  • Authentication Audit Logs: Track all authentication attempts (success/failure)
  • Request Logs: Full request/response logging with metadata
  • Collaboration History: Git-style version control for workspace changes
  • Configuration Changes: Track all configuration modifications
  • Plugin Activity: Monitor plugin execution and security events

Full Documentation: See Audit Trails Guide for complete audit logging configuration and usage.

Troubleshooting Security

Common Issues

Encryption, Authentication, or Key Store Issues

There are no dedicated encryption, keys, or auth CLI commands. Inspect and validate the effective configuration instead:

# Validate the configuration file (including encryption and auth sections)
mockforge config validate --config mockforge.yaml --warnings

# Show the effective configuration after env var overrides
mockforge config show --config mockforge.yaml

Debug Mode

Enable security debug logging:

RUST_LOG=mockforge_core::encryption=debug,mockforge_core::auth=debug mockforge serve

This comprehensive security system ensures that MockForge can be safely used in enterprise environments while protecting sensitive mock data and configurations.

Directory Synchronization

MockForge’s sync daemon enables automatic synchronization between workspace files and MockForge’s internal storage, allowing you to work with your mock API definitions as files and keep them in version control.

Overview

The sync daemon monitors a directory for .yaml and .yml files and automatically imports them into MockForge workspaces. This enables:

  • File-based workflows: Edit workspace files with your favorite text editor
  • Version control: Keep workspace definitions in Git
  • Team collaboration: Share workspaces via Git repositories
  • Automated workflows: CI/CD integration and automated deployment
  • Real-time feedback: See exactly what’s being synced as it happens

How It Works

The sync daemon provides bidirectional synchronization:

  1. Monitors Directory: Watches for file changes in the specified workspace directory
  2. Detects Changes: Identifies created, modified, and deleted .yaml/.yml files
  3. Imports Automatically: Parses and imports valid MockRequest files into workspaces
  4. Provides Feedback: Shows clear, real-time output of all sync operations

What Gets Synced

  • File Types: Only .yaml and .yml files
  • File Format: Files must be valid MockRequest YAML
  • Subdirectories: Monitors all subdirectories recursively
  • Exclusions: Skips hidden files (starting with .)

Getting Started

Starting the Sync Daemon

Use the CLI to start the sync daemon:

# Basic usage
mockforge sync --workspace-dir ./my-workspace

# Short form
mockforge sync -w ./my-workspace

# With custom configuration
mockforge sync --workspace-dir ./workspace --config sync-config.yaml

What You’ll See

When you start the sync daemon:

🔄 Starting MockForge Sync Daemon...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 Workspace directory: ./my-workspace

ℹ️  What the sync daemon does:
   • Monitors the workspace directory for .yaml/.yml file changes
   • Automatically imports new or modified request files
   • Syncs changes bidirectionally between files and workspace
   • Skips hidden files (starting with .)

🔍 Monitoring for file changes...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✅ Sync daemon started successfully!
💡 Press Ctrl+C to stop

Real-time Feedback

As files change, you’ll see detailed output:

🔄 Detected 1 file change in workspace 'default'
  ➕ Created: new-endpoint.yaml
     ✅ Successfully imported

🔄 Detected 2 file changes in workspace 'default'
  📝 Modified: user-api.yaml
     ✅ Successfully updated
  🗑️  Deleted: old-endpoint.yaml
     ℹ️  Auto-deletion from workspace is disabled

Directory Organization

You can organize your workspace files however you like. The sync daemon monitors all subdirectories recursively:

my-workspace/
├── api-v1/
│   ├── users.yaml
│   ├── products.yaml
│   └── orders.yaml
├── api-v2/
│   ├── users.yaml
│   └── graphql.yaml
├── internal/
│   └── admin.yaml
└── shared/
    └── auth.yaml

All .yaml and .yml files will be monitored and imported automatically.

File Format

Each file should contain a valid MockRequest in YAML format:

id: "get-users"
name: "Get Users"
method: "GET"
path: "/api/users"
headers:
  Content-Type: "application/json"
response_status: 200
response_body: |
  [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ]

Usage Examples

Git Integration

Keep your workspaces in version control:

# 1. Create a Git repository for your workspaces
mkdir api-mocks
cd api-mocks
git init

# 2. Start the sync daemon
mockforge sync --workspace-dir .

# 3. Create or edit workspace files
vim user-endpoints.yaml

# 4. Commit and push changes
git add .
git commit -m "Add user endpoints"
git push origin main

# 5. Team members can pull changes
# The sync daemon will automatically import updates

Development Workflow

Use the sync daemon during active development:

# Terminal 1: Start sync daemon
mockforge sync --workspace-dir ./workspaces

# Terminal 2: Edit files
vim ./workspaces/new-feature.yaml

# Changes are automatically imported
# You'll see real-time feedback in Terminal 1

CI/CD Integration

Automate workspace deployment:

#!/bin/bash
# deploy-mocks.sh

# Pull latest workspace definitions from Git
git pull origin main

# Start sync daemon in background
mockforge sync --workspace-dir ./workspaces &
SYNC_PID=$!

# Wait for initial sync
sleep 5

# Start MockForge server
mockforge serve --config mockforge.yaml

# Cleanup on exit
trap "kill $SYNC_PID" EXIT

Best Practices

1. Use Version Control

Keep workspace files in Git for team collaboration:

# Create a .gitignore to exclude temporary files
echo ".DS_Store" >> .gitignore
echo "*.swp" >> .gitignore
echo "*.tmp" >> .gitignore

# Commit workspace definitions
git add *.yaml
git commit -m "Add workspace definitions"

2. Organize Files Logically

Structure your workspace files for clarity:

workspaces/
├── production/         # Production endpoints
│   ├── users-api.yaml
│   └── orders-api.yaml
├── staging/           # Staging endpoints
│   └── beta-features.yaml
└── development/       # Development/experimental
    └── new-feature.yaml

3. Use Descriptive Filenames

Name files based on what they contain:

✅ Good:
   - user-authentication.yaml
   - product-catalog-api.yaml
   - payment-processing.yaml

❌ Bad:
   - endpoint1.yaml
   - test.yaml
   - temp.yaml

4. Keep Sync Daemon Running

Run the sync daemon continuously during development:

# Use a terminal multiplexer like tmux
tmux new -s mockforge-sync
mockforge sync --workspace-dir ./workspaces

# Detach with Ctrl+B then D
# Reattach with: tmux attach -t mockforge-sync

5. Monitor Sync Output

Pay attention to the sync daemon’s output:

  • ✅ Green checkmarks: Files imported successfully
  • ⚠️ Warning icons: Import failed, check file format
  • 🔄 Change notifications: Shows what’s being synced
  • ❌ Error messages: Indicate issues that need fixing

6. Handle Errors Promptly

When you see errors, fix them immediately:

❌ Detected error:
  📝 Modified: broken-endpoint.yaml
     ⚠️  Failed to import: File is not a recognized format

Action: Check the file syntax and fix YAML formatting

Troubleshooting

Files Not Being Imported

Check file extension:

# Only .yaml and .yml files are monitored
ls -la workspaces/
# Ensure files end with .yaml or .yml

Verify file format:

# Files must be valid MockRequest YAML
cat workspaces/my-file.yaml
# Check for proper YAML syntax and required fields

Check for hidden files:

# Hidden files (starting with .) are ignored
# Rename: .hidden.yaml → visible.yaml
mv .hidden.yaml visible.yaml

Permission Errors

# Ensure MockForge can read the directory
chmod 755 workspaces/
chmod 644 workspaces/*.yaml

# Check ownership
ls -la workspaces/

Changes Not Detected

Verify sync daemon is running:

# Check if the process is still active
ps aux | grep "mockforge sync"

Check filesystem notifications:

# Some network filesystems don't support notifications
# Try editing locally instead of over NFS/SMB

Restart sync daemon:

# Stop with Ctrl+C, then restart
mockforge sync --workspace-dir ./workspaces

YAML Syntax Errors

When files fail to import due to syntax errors:

# Use a YAML validator
yamllint workspaces/problematic-file.yaml

# Common issues:
# - Incorrect indentation
# - Missing quotes around special characters
# - Invalid escape sequences

Debug Logging

Enable detailed logging to see what’s happening:

# Enable debug logs for sync watcher
RUST_LOG=mockforge_core::sync_watcher=debug mockforge sync --workspace-dir ./workspaces

# Enable trace-level logs for maximum detail
RUST_LOG=mockforge_core::sync_watcher=trace mockforge sync --workspace-dir ./workspaces

# Log to a file
RUST_LOG=mockforge_core::sync_watcher=debug mockforge sync --workspace-dir ./workspaces 2>&1 | tee sync.log

Getting Help

If you’re still having issues:

  1. Check the sync daemon output for error messages
  2. Enable debug logging to see detailed information
  3. Verify file format matches MockRequest YAML structure
  4. Check file permissions and ownership
  5. Try with a minimal test file to isolate the issue

Example minimal test file:

# test-endpoint.yaml
id: "test"
name: "Test Endpoint"
method: "GET"
path: "/test"
response_status: 200
response_body: '{"status": "ok"}'

Save this file in your workspace directory and verify it gets imported successfully.

Admin UI

MockForge Logo

MockForge Admin UI is a modern React-based dashboard that provides comprehensive administrative capabilities for your MockForge instances. Built with Shadcn UI components and designed for power users, it eliminates the need for manual file editing while providing enhanced functionality and user experience.

Overview

The Admin UI replaces the legacy static HTML interface with a rich, interactive React application that offers:

  • Service Management: Enable/disable services and routes with granular control
  • Fixture Management: Visual editing, diffing, and organization of mock data
  • Live Monitoring: Real-time logs and performance metrics
  • Authentication: Secure role-based access control
  • Advanced Search: Full-text search across services, fixtures, and logs
  • Bulk Operations: Manage multiple services simultaneously

Getting Started

Enabling the Admin UI

Start MockForge with the --admin flag:

mockforge serve --admin

Access the interface at http://localhost:9080 (or the port set with --admin-port).

Authentication

The Admin UI includes secure authentication with three built-in roles:

Admin Role

  • Username: admin
  • Password: admin123
  • Permissions: Full access to all features

Editor Role

  • Username: editor
  • Password: editor123
  • Permissions: Create/edit fixtures, routes, and configuration (no user management)

Viewer Role

  • Username: viewer
  • Password: viewer123
  • Permissions: Read-only access to dashboard, logs, and metrics

First Login

  1. Navigate to the admin URL
  2. Enter your credentials or click “Demo Admin” for quick access
  3. The interface will load with role-appropriate navigation

Core Features

Dashboard

The dashboard provides an overview of your MockForge instance:

  • System Status: CPU, memory usage, uptime, and active threads
  • Server Status: HTTP, WebSocket, and gRPC server health
  • Recent Requests: Latest API calls with response times and status codes
  • Quick Stats: Total routes, fixtures, and active connections

Service Management

Manage your mock services without editing configuration files:

Service Controls

  • Service Toggle: Enable/disable entire services
  • Route Toggle: Granular control over individual endpoints
  • Bulk Operations: Enable/disable multiple services at once
  • Tag Filtering: Filter services by tags for organized management

Service Information

  • Request counts and error rates per route
  • Response time averages
  • HTTP method indicators (GET, POST, PUT, DELETE)
  • gRPC service paths
// Example: Toggle a service programmatically
const { updateService } = useServiceStore();
updateService('user-service', { enabled: false });

Fixture Management

Complete fixture lifecycle management through the web interface:

File Operations

  • Tree View: Hierarchical organization of fixture files
  • Drag & Drop: Move fixtures between folders
  • Inline Rename: Click to edit fixture names
  • Rich Editor: Monaco-style editing with syntax highlighting

Content Management

  • Real-time Editing: Live preview of fixture content
  • Version Control: Track changes with version numbers
  • Auto-save: Ctrl+S keyboard shortcut for quick saves
  • File Metadata: Size, modification dates, and route associations

Visual Diff

  • Change Detection: Automatic diff generation on content changes
  • Side-by-side View: Color-coded comparison of old vs new content
  • Change Statistics: Count of added, removed, and modified lines
  • Diff History: Review previous changes with timestamps

Live Logs

Monitor your MockForge instance in real-time:

Log Streaming

  • Real-time Updates: Live log feed with configurable refresh intervals
  • Auto-scroll: Smart scrolling with pause/resume controls
  • Connection Status: Visual indicators for WebSocket health

Advanced Filtering

  • Method Filter: Filter by HTTP methods (GET, POST, etc.)
  • Status Code Filter: Focus on specific response codes
  • Path Search: Full-text search across request paths
  • Time Range: Filter logs by time windows (1h, 6h, 24h, 7d)

Log Details

  • Request Inspection: Click any log entry for detailed view
  • Headers & Timing: Complete request/response metadata
  • Error Analysis: Detailed error messages and stack traces
  • Export Options: Download filtered logs for analysis

Performance Metrics

Comprehensive performance monitoring and analysis:

Latency Analysis

  • Histogram Visualization: Response time distribution across buckets
  • Percentile Metrics: P50, P95, and P99 latency measurements
  • Service Comparison: Compare performance across different services
  • Color-coded Buckets: Visual indicators for fast (green), medium (yellow), and slow (red) responses

Failure Analysis

  • Success/Failure Ratios: Pie chart visualization of request outcomes
  • Status Code Distribution: Bar chart of HTTP response codes
  • Error Rate Tracking: Percentage of failed requests over time
  • SLA Monitoring: Visual indicators for SLA compliance

Real-time Updates

  • Auto-refresh: Metrics update every 30 seconds
  • Manual Refresh: Force immediate data refresh
  • Performance Alerts: Automatic warnings for high error rates or latency

Advanced Features

The Admin UI provides access to many advanced MockForge features:

  • Chaos Lab: Interactive network condition simulation with real-time latency visualization
  • Reality Slider: Unified control for adjusting mock environment realism
  • Scenario State Machine Editor: Visual flow editor for creating state machines
  • Time Travel Controls: Virtual clock controls for temporal simulation
  • Contract Diff Dashboard: Visualize and analyze API contract mismatches
  • Voice Interface: Create APIs using natural language commands

For detailed documentation on these features, see the Advanced Features section.

Authentication & Authorization

JWT-based Security

  • Token Authentication: Secure JWT tokens with automatic refresh
  • Session Persistence: Login state survives browser refresh
  • Auto-logout: Automatic logout on token expiration

Role-based Access Control

  • Admin Features: Full read/write access to all functionality
  • Viewer Restrictions: Read-only access to monitoring features
  • Navigation Adaptation: Menu items adjust based on user role
  • Permission Guards: Graceful handling of unauthorized access

Search & Filtering

  • Service Search: Find services by name, route paths, or tags
  • Fixture Search: Search fixture names, paths, and content
  • Log Search: Full-text search across log messages and metadata

Advanced Filters

  • Tag-based Filtering: Group services by functional tags
  • Time-based Filtering: Filter data by time ranges
  • Status Filtering: Focus on specific response codes or error states
  • Persistent Filters: Maintain filter state across navigation

Bulk Operations

Service Management

# Enable all services in a tag group
services.filter(s => s.tags.includes('api'))
  .forEach(s => updateService(s.id, { enabled: true }));

Fixture Operations

  • Batch Selection: Select multiple fixtures for operations
  • Bulk Rename: Apply naming patterns to multiple files
  • Mass Delete: Remove multiple fixtures with confirmation

Validation Management

The Admin UI provides comprehensive validation controls for OpenAPI request validation:

Validation Mode Control

  • Global Mode Toggle: Switch between off, warn, and enforce validation modes
  • Per-Route Overrides: Set custom validation rules for specific endpoints
  • Real-time Application: Changes take effect immediately without server restart

Validation Monitoring

  • Error Statistics: View validation failure rates and error types
  • Route-specific Metrics: See which endpoints are failing validation
  • Error Details: Inspect detailed validation error messages

Advanced Validation Features

  • Aggregate Error Reporting: Combine multiple validation errors into single responses
  • Response Validation: Validate response payloads against OpenAPI schemas
  • Admin Route Exclusion: Skip validation for admin UI routes when configured
// Example: Update validation mode programmatically
const { updateValidation } = useValidationStore();
updateValidation({
  mode: 'warn',
  aggregate_errors: true,
  overrides: {
    'GET /health': 'off',
    'POST /api/users': 'enforce'
  }
});

Configuration

Environment Variables

# Admin UI port (default: 9080)
MOCKFORGE_ADMIN_PORT=9080

# Enable the Admin UI
MOCKFORGE_ADMIN_ENABLED=true

Auth, session timeout, JWT secrets, and resource limits are YAML-only — configure under admin.* in mockforge.yaml.

Custom Authentication

Replace the default authentication with your own system:

#![allow(unused)]
fn main() {
// Custom auth provider
pub struct CustomAuthProvider {
    // Your authentication implementation
}

impl AuthProvider for CustomAuthProvider {
    fn authenticate(&self, username: &str, password: &str) -> Result<User> {
        // Your authentication logic
    }
}
}

Theming

The Admin UI supports light and dark themes with CSS custom properties:

:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 221.2 83.2% 53.3%;
  /* ... additional theme variables */
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  /* ... dark theme overrides */
}

API Integration

REST Endpoints

The Admin UI communicates with MockForge through RESTful APIs:

The embedded admin server exposes its API under /__mockforge/* (the hosted cloud registry uses a different /api/v1/* prefix; see the Cloud Workspaces guide for that surface).

# Service & route listing
GET    /__mockforge/routes
GET    /__mockforge/server-info

# Fixture management
GET    /__mockforge/fixtures
POST   /__mockforge/fixtures
PUT    /__mockforge/fixtures/{id}
DELETE /__mockforge/fixtures/{id}

# Authentication
POST   /__mockforge/auth/login
POST   /__mockforge/auth/refresh
POST   /__mockforge/auth/logout
GET    /__mockforge/auth/me

# Logs and metrics
GET    /__mockforge/logs
GET    /__mockforge/metrics

Server-Sent Events

Real-time features stream over SSE:

# Live log streaming
GET /__mockforge/logs/sse

Troubleshooting

Common Issues

Authentication Problems

# Verify admin credentials against the embedded admin server
curl -X POST http://localhost:9080/__mockforge/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}'

If the curl above returns a token but the browser login page still fails, the UI bundle was built in cloud mode. The OSS docker image must ship a local bundle — see crates/mockforge-ui/ui/.env.production.example; .env.production is gitignored on purpose.

Log Stream Connection Issues

# Check the log SSE endpoint
curl -N http://localhost:9080/__mockforge/logs/sse

# Verify proxy configuration if behind a reverse proxy
ProxyPass /__mockforge/ http://localhost:9080/__mockforge/

Performance Issues

For large fixture sets / high-traffic dashboards, enable Prometheus metrics with --metrics --metrics-port 9090 to track admin server overhead. Memory tuning is YAML-only (admin.memory_limit_mb).

Debug Mode

Enable debug logging for troubleshooting:

MOCKFORGE_LOG_LEVEL=debug mockforge serve --admin

Browser Compatibility

The Admin UI requires modern browsers with support for:

  • ES2020 features
  • WebSocket API
  • CSS Grid and Flexbox
  • Local Storage

Best Practices

Security

  • Change default admin credentials in production
  • Use HTTPS for admin interface in production
  • Configure appropriate session timeouts
  • Regularly rotate JWT secrets

Performance

  • Use filtering to limit large datasets
  • Enable auto-scroll only when monitoring actively
  • Clear old logs periodically to improve performance
  • Monitor memory usage with large fixture files

Organization

  • Use descriptive service and fixture names
  • Organize fixtures in logical folder structures
  • Apply consistent tagging to services
  • Document fixture purposes in comments

Examples

Service Management Workflow

// 1. Filter services by tag
const apiServices = services.filter(s => s.tags.includes('api'));

// 2. Enable all API services
apiServices.forEach(service => {
  updateService(service.id, { enabled: true });
});

// 3. Disable specific routes within services
apiServices.forEach(service => {
  service.routes
    .filter(route => route.path.includes('/internal'))
    .forEach(route => {
      const routeId = `${route.method}-${route.path}`;
      toggleRoute(service.id, routeId, false);
    });
});

Fixture Management Workflow

// 1. Create new fixture
const newFixture = {
  id: 'user-profile-success',
  name: 'user-profile.json',
  path: 'http/get/users/profile/user-profile.json',
  content: JSON.stringify({
    id: '{{uuid}}',
    name: '{{faker.name.fullName}}',
    email: '{{faker.internet.email}}',
    created_at: '{{now}}'
  }, null, 2)
};

// 2. Add to store
addFixture(newFixture);

// 3. Associate with route
updateFixture(newFixture.id, {
  ...newFixture.content,
  route_path: '/api/users/profile',
  method: 'GET'
});

This comprehensive guide covers all aspects of the MockForge Admin UI, from basic usage to advanced configuration and troubleshooting. The interface provides a complete administrative solution that eliminates the need for manual file editing while offering enhanced functionality and user experience.

IDE Integration

MockForge provides first-class IDE integration to enhance your development workflow. This guide covers the VS Code extension and its features.

VS Code Extension

The MockForge VS Code extension brings the power of MockForge directly into your editor, providing real-time mock management, validation, and preview capabilities.

Installation

Install the extension from the VS Code Marketplace:

  1. Open VS Code
  2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
  3. Search for “MockForge”
  4. Click Install

Or install via command line:

code --install-extension saasy-solutions.mockforge-vscode

Configuration

Configure the extension in VS Code settings:

{
  "mockforge.serverUrl": "http://localhost:3000",
  "mockforge.autoConnect": true,
  "mockforge.showNotifications": true,
  "mockforge.inlinePreview.enabled": true
}

Settings:

  • mockforge.serverUrl: MockForge server URL (default: http://localhost:3000)
  • mockforge.autoConnect: Automatically connect on startup (default: true)
  • mockforge.showNotifications: Show notifications for mock changes (default: true)
  • mockforge.inlinePreview.enabled: Enable inline preview of mock responses (default: true)

Features

Peek Mock Response

Hover over API endpoint references in your code to see mock responses inline.

Supported Patterns:

  • fetch('/api/users')
  • axios.get('/api/products')
  • http.get('/api/orders')
  • Endpoint paths in mockforge.yaml files

Usage:

  1. Hover over any API endpoint reference in your code
  2. See the mock response (headers and body) in a tooltip
  3. Click “Open in Playground” to test the endpoint interactively

Example:

// Hover over this endpoint to see the mock response
const response = await fetch('/api/users');

The hover tooltip will show:

  • Response headers
  • Response body (formatted JSON)
  • Link to open in MockForge Playground

Config Validation

Get real-time validation for your mockforge.yaml files with inline error reporting.

Features:

  • Inline error reporting with accurate line/column positions
  • Validates against JSON Schema generated from MockForge config types
  • Supports multiple config types:
    • Main config (mockforge.yaml)
    • Reality config (reality/*.yaml)
    • Persona config (personas/*.yaml)
    • Blueprint config (blueprint.yaml)
  • Auto-detects schema type based on file name and location
  • Helpful error messages for:
    • Missing required fields
    • Type mismatches
    • Invalid enum values
    • Format errors (email, uri, etc.)
    • Pattern mismatches

Example:

# mockforge.yaml
reality:
  level: invalid_level  # ❌ Error: Invalid reality level

The extension will show an inline error:

Invalid reality level: invalid_level. Valid values: static, light, moderate, high, chaos

Mocks Explorer

Visual tree view of all your mocks with real-time WebSocket updates.

Features:

  • Browse all mocks in a tree view
  • Color-coded by HTTP method (GET, POST, PUT, DELETE, etc.)
  • Real-time updates when mocks change
  • Context menu actions:
    • Edit Mock
    • Delete Mock
    • Toggle Mock (enable/disable)
    • View Details

Usage:

  1. Open the MockForge sidebar (click the MockForge icon in the activity bar)
  2. Browse your mocks in the “Mocks Explorer” view
  3. Click on a mock to see details
  4. Right-click for context menu actions

Server Control

Monitor your MockForge server status and statistics.

Features:

  • Connection status indicator
  • Server version and port
  • Uptime and request count
  • Active mocks count
  • Quick actions to start/stop/restart server

Usage:

  1. Open the “Server Control” panel in the MockForge sidebar
  2. View server statistics
  3. Use quick actions to manage the server

Playground Integration

Quick access to MockForge Playground from hover tooltips.

Usage:

  1. Hover over an API endpoint reference
  2. Click “Open in Playground” in the tooltip
  3. The MockForge Admin UI playground opens in your browser
  4. The endpoint method and path are pre-filled

Workflow Integration

Development Workflow

  1. Start MockForge server: mockforge serve --admin
  2. Open VS Code: The extension auto-connects
  3. Edit config files: Get real-time validation
  4. Hover over endpoints: See mock responses inline
  5. Test in Playground: Click “Open in Playground” from hover tooltips

Config Validation Workflow

  1. Edit mockforge.yaml: Start typing your configuration
  2. See inline errors: Validation happens in real-time
  3. Fix errors: Follow the error messages to correct issues
  4. Generate schemas (optional): Run mockforge schema generate to create local schemas

Mock Management Workflow

  1. View mocks: Open Mocks Explorer
  2. Create mock: Click “+” icon or use command palette
  3. Edit mock: Right-click → Edit Mock
  4. Test mock: Hover over endpoint reference to see response
  5. Open in Playground: Click link in hover tooltip

Troubleshooting

Extension Not Connecting

  1. Check that MockForge server is running
  2. Verify mockforge.serverUrl setting is correct
  3. Check VS Code output panel for connection errors
  4. Try restarting the extension: Command Palette → “MockForge: Restart Extension”

Validation Not Working

  1. Ensure you have a mockforge.yaml file open
  2. Check that schemas are available:
    • Look for schemas/ directory in workspace
    • Or run mockforge schema generate to create schemas
  3. Check VS Code output panel for validation errors

Hover Preview Not Showing

  1. Ensure mockforge.inlinePreview.enabled is true
  2. Check that MockForge server is connected
  3. Verify the endpoint path matches a configured mock
  4. Try hovering over different endpoint patterns

Load Testing

MockForge ships first-class load-testing tools that work against any HTTP API — your real backend, a MockForge mock, or a hosted test environment. Two commands, two purposes:

CommandWhen to use
mockforge benchOpenAPI-driven k6 script generation. Best for ramp/spike/soak/constant scenarios across realistic, schema-aware traffic.
mockforge bench-chunkedNative Rust generator for guaranteed Transfer-Encoding: chunked request bodies — chunk size, total size, inter-chunk delay all controllable.

The full reference lives at docs/bench-command-examples.md and docs/LOAD_TESTING_GUIDE.md. This chapter covers the patterns most teams reach for first.

mockforge bench — OpenAPI-driven k6

Quick start

mockforge bench \
  --spec api.yaml \
  --target http://localhost:3000 \
  --duration 60 --vus 10 \
  --scenario ramp-up

That generates a k6 script from api.yaml, writes it to bench-results/, and runs it. The script:

  • Walks every operation in the spec
  • Generates realistic placeholder bodies / headers / path params
  • Tracks http_req_duration and http_req_failed thresholds
  • Prints a summary at the end (and writes summary.json)

Load scenarios

ScenarioShapeUse case
constantFlat at --vusSteady-state throughput
ramp-up0 → vus → 0Find capacity ceiling
spikeSudden burstTest autoscaling response
stressAggressive ramp past vusFind breaking point
soakLong duration at moderate loadMemory leaks / degradation

Auth and custom headers

mockforge bench --spec api.yaml --target https://api.example.com \
  --auth "Bearer $TOKEN" \
  --headers "X-Tenant: acme,X-Region: us-east-1"

Operation filtering

Test only specific endpoints:

# Specific operation
mockforge bench --spec api.yaml --target ... \
  --operations "GET /users,POST /orders"

# By method
mockforge bench --spec api.yaml --target ... \
  --operations "GET"

# Wildcards
mockforge bench --spec api.yaml --target ... \
  --operations "* /api/v1/*"

Generate-only (don’t run)

mockforge bench --spec api.yaml --target ... \
  --generate-only --script-output my-load-test.js

Edit the script by hand, then run with k6 directly. Useful for CI/CD where the test infrastructure runs k6 on its own.

Multi-target

mockforge bench --spec api.yaml --targets-file targets.txt \
  --max-concurrency 5 --results-format both

targets.txt lists one URL per line; bench runs against all of them in parallel and produces per-target + aggregated reports.

mockforge bench-chunked — native chunked traffic

When you need real Transfer-Encoding: chunked request bodies on the wire, mockforge bench (k6/Go-based) may fall back to Content-Length because Go’s HTTP transport decides chunking from body type. bench-chunked bypasses that — it builds a streaming body via hyper’s Body::wrap_stream with no declared length, so the wire is always chunked.

mockforge bench-chunked \
  --target http://localhost:3000/upload \
  --concurrency 10 --duration 60 \
  --chunk-size-bytes 4096 \
  --total-size-bytes 10485760 \
  --chunk-interval-ms 50 \
  --header "Authorization: Bearer $TOKEN"
FlagMeaning
--targetURL to POST chunked bodies at
--targets-fileBench every target in the file in parallel instead of one --target
--max-concurrencyMax targets running at once with --targets-file (default 10)
--methodPOST (default), PUT, or PATCH
--concurrencyConcurrent uploads per target: each worker sends one chunked request at a time and starts the next as soon as it finishes
--durationRun length (30s, 15m, …); per operation with --spec
--chunk-size-bytesBytes per chunk emitted into the body stream
--total-size-bytesTotal body size per request
--chunk-interval-msPause between chunks (0 = back-to-back); the first chunk goes out with the headers
--rpsCap on request starts per second, per target (shared by its workers)
--cpsNew TCP/TLS connection per request, so connections/s = requests/s
--rounds / --repeat-untilRe-run the whole pass N times / until a wall-clock duration elapses
--keep-roundsKeep only the newest N round_* dirs during a campaign
--headerExtra Name: Value header; may be repeated
--insecureSkip TLS certificate verification

Request body. With a JSON Content-Type (application/json or any +json type, from --header or a targets-file headers entry), each request body is a valid JSON document of exactly --total-size-bytes: the spec-generated request body for the operation (with --spec) plus a "_padding" string field that fills it to size. Any other content type gets X filler bytes, which suits application/octet-stream uploads.

Common patterns

Slow upload simulation — high --chunk-interval-ms keeps the connection open for minutes per request, stressing the server’s idle/slow-connection handling:

mockforge bench-chunked --target http://server/upload \
  --concurrency 50 --duration 300 \
  --chunk-size-bytes 256 --total-size-bytes 65536 \
  --chunk-interval-ms 500

Large body soak — find the server’s max-body-size limits and memory behavior:

mockforge bench-chunked --target http://server/upload \
  --concurrency 5 --duration 180 \
  --chunk-size-bytes 1048576 --total-size-bytes 1073741824

Multiple targets — send chunked traffic to every server in a targets file at once. The file format is the same as mockforge bench --targets-file (one URL per line, or JSON with per-target auth, headers and spec). Without --spec each entry is a full endpoint URL; with --spec each entry is a base URL and every POST/PUT/PATCH operation runs against it:

mockforge bench-chunked --targets-file targets.txt --spec api.yaml \
  --max-concurrency 5 --concurrency 10 --duration 10m \
  --chunk-size-bytes 4096 --total-size-bytes 1048576 --export-requests

Output lines are prefixed with [target_N]. Per-target files go to <output>/target_N/, and <output>/chunked-multi-target-summary.json rolls up request, byte and status-code totals for every target.

How the numbers combine. --max-concurrency × --concurrency is the peak number of uploads in flight (e.g. 5 × 10 = 50). With --spec, every target gets every POST/PUT/PATCH operation; operations run one after another per target, each for --duration. If the targets file has more entries than --max-concurrency, the extra targets wait for a running one to finish all of its operations. Each request lasts at least (total_size_bytes / chunk_size_bytes - 1) × chunk_interval_ms, so without --rps the per-target request rate is roughly concurrency / request_seconds and the per-target bandwidth is roughly concurrency × chunk_size_bytes / chunk_interval_ms. A request in flight when --duration expires is allowed to finish.

Fixed rate and longevity — --rps paces request starts per target, --cps makes each one a new connection, and --repeat-until loops the whole pass (each round in <output>/round_N/, per-round stats in <output>/campaign.jsonl and <output>/round-summaries/):

mockforge bench-chunked --targets-file targets.txt --spec api.yaml \
  --concurrency 20 --rps 2 --cps --duration 15m \
  --repeat-until 24h --keep-rounds 3 --export-requests

--rps is a ceiling: with 128 s uploads and --concurrency 10, a target can only start about 10 / 128 ≈ 0.08 requests per second, so raise --concurrency to reach higher rates.

Chunked + chaos matching — pair with chunked_only: true in fault_injection.request_matcher (see Chaos Engineering) to inject faults only on chunked traffic:

# server config
fault_injection:
  enabled: true
  http_errors: [503]
  http_error_probability: 0.5
  request_matcher:
    chunked_only: true
# in another terminal
mockforge bench-chunked --target http://localhost:3000/upload \
  --concurrency 10 --duration 60 \
  --total-size-bytes 1048576

Pairing with chaos

Load testing alone tells you the throughput your server handles. Pair it with chaos engineering to test how it behaves when things go wrong:

# Terminal 1
mockforge serve --spec api.yaml --chaos --chaos-scenario cascading_failure

# Terminal 2
mockforge bench --spec api.yaml --target http://localhost:3000 \
  --duration 5m --vus 50

Watch the TUI dashboard to see CPU / memory / error-rate spike as chaos fires. Set MOCKFORGE_METRICS_LOG_FILE=metrics.csv for a persistent record of multi-hour runs.

Watching the run

While a bench is running, you usually want to monitor:

  • mockforge-tui — live dashboard with current and peak CPU, memory, error rate. Auto-refreshes every 2 s.
  • CSV metrics log — MOCKFORGE_METRICS_LOG_FILE=path appends a row per 10 s. Persistent record for soak tests.
  • k6 stdout / summary.json — at the end of the bench run.
  • Prometheus — mockforge serve --metrics --metrics-port 9090, scrape with your usual stack.

CI/CD

#!/bin/bash
set -e

# Start MockForge against staging
mockforge serve --spec api.yaml &
SERVER=$!
trap "kill $SERVER" EXIT

# Wait for ready
until curl -sf http://localhost:3000/__health > /dev/null; do sleep 1; done

# Run bench with thresholds enforced
mockforge bench --spec api.yaml \
  --target http://localhost:3000 \
  --duration 30 --vus 20 \
  --threshold-percentile 95 \
  --threshold-ms 250 \
  --max-error-rate 0.01

# Exit code propagates from k6 — fails the build if thresholds break

Where to go next

WAF Testing

mockforge bench can drive traffic at a WAF, reverse proxy or API gateway and assert on the status codes that come back. This page covers where the requests come from, because that is the part that decides whether your rules are actually exercised.

Two ways to supply traffic

--wafbench-dir accepts a file, a directory or a glob, in either of two shapes.

1. A WAFBench / CRS document — a meta: mapping plus a tests: list. This is the format used by the OWASP Core Rule Set regression suite and by WAFBench.

2. A simple list of cases:

- title: unsupported response_type with redirect_uri blocked
  request:
    method: GET
    uri: /oauth/authorize?response_type=totally-unsupported&redirect_uri=https%3A%2F%2Fevil.example%2Flanding
    headers:
      X-Test: example
  expected: 403

expected accepts 403, a list [403, 406], or { status: 403 }. method defaults to GET.

Two ways to send it

This is the distinction that matters most, and picking the wrong one is the usual reason a rule never fires.

Default: payload extraction

By default a case’s uri is treated as a CRS attack string that happens to be carried in a query parameter. mockforge keeps only the first parameter’s value, discards the path, and re-attaches that value to endpoints taken from --spec as ?test=<payload>.

So this case:

uri: /oauth/authorize?response_type=totally-unsupported&redirect_uri=https%3A%2F%2Fevil.example%2Flanding&state=s1

goes out roughly as:

GET <endpoint-from-spec>?test=totally-unsupported

redirect_uri and state are gone, and so is the path. That is correct for CRS files, where a test is one attack string and the endpoint it hits is irrelevant. It is wrong when your rule inspects a particular parameter, or several parameters together.

--wafbench-verbatim: send it as written

mockforge bench \
  --wafbench-dir ./traffic/oauth.yaml \
  --wafbench-verbatim \
  --target https://waf.example.com

Method, full URI, headers and body are sent exactly as given. No extraction, no path substitution, no test= parameter, no cycling through spec endpoints, and no attack payloads appended.

The URI is preserved byte for byte, including percent-encoding. Query parameters are deliberately not parsed and re-joined, because for charset, traversal and double-encoding cases the encoding is the payload.

Use verbatim mode when your rule chains on named parameters, for example:

SecRule ARGS:redirect_uri "@unconditionalMatch" "id:1,phase:2,block,chain"
    SecRule ARGS:response_type "!@rx ^(?:code|token|none|id_token)$" "t:none"

Under default extraction this rule can never fire, because redirect_uri never reaches the wire.

Which URLs get hit

FlagsRequests sent
--wafbench-dir + --specPayloads extracted from the traffic file, attached as ?test= to endpoints from the spec
--wafbench-dir + --spec + --wafbench-cycle-allSame targets; every payload is used in turn instead of sampled at random
--wafbench-dir + --wafbench-verbatimOnly the traffic file’s own requests, as written. No spec needed
--wafbench-dir + --wafbench-verbatim + --specSame as above. The spec is used only to resolve --base-path
--wafbench-dir + --wafbench-verbatim + --targets-fileSame YAML requests, one k6 run per target. Spec still optional

--wafbench-cycle-all affects payload selection only. It does not change which URLs are targeted, and it has no effect in verbatim mode, where there is no payload pool.

--security-test is ignored under --wafbench-verbatim, with a warning: appending attack payloads would contradict sending the cases as written.

Baselines and omit_rule

WAFBench files sometimes mark a case with omit_rule: true, meaning “send this request with the rule under test disabled, to prove the rule is what blocks it”.

mockforge cannot honour that, because disabling a rule is WAF-side configuration. Such cases are skipped, with a warning naming the case.

They are skipped rather than sent because sending one produces a request that is byte-identical to its non-omitted twin while asserting the opposite status: one of the pair would always fail, whether or not the rule works, which is precisely what a baseline is supposed to rule out.

To get a real baseline, run the same file twice against two WAF configurations, one with the rule enabled and one without, and compare.

Reading the results

A WAF under test legitimately rejects most traffic, so the k6 abort-on-error safety valve will cut a run short. Disable it for WAF work:

mockforge bench --wafbench-dir ./traffic --wafbench-verbatim \
  --target https://waf.example.com --no-abort-on-error

If you only want the generated script, add --generate-only and inspect k6-script.js in --output.

Chaos Engineering

MockForge ships a runtime chaos engineering surface that injects controlled failures, delays, and resource constraints into your mock or proxy server. Use it to test how clients behave when the real backend gets slow, returns errors, drops the connection, sends partial responses, or rate-limits you.

Two related but distinct features: this chapter covers the YAML / runtime config (loaded by mockforge serve). For the in-app Chaos Lab UI and predefined network profiles, see the separate page. Many users want both — the YAML config for headless test runs and the UI for interactive exploration.

The full reference (every config knob, every API endpoint, every predefined scenario) lives at docs/CHAOS_ENGINEERING.md. This chapter focuses on the patterns most teams reach for first.

What you can inject

CategoryExamples
LatencyFixed delay, random range, jitter, probability-based
HTTP errorsAny status code, configurable probability, error pattern (burst / random / sequential)
Connection errorsHTTP 503 (default), TCP RST, TCP FIN — at the wire level
TimeoutsReal tokio::sleep then 504 Gateway Timeout
Partial responsesBody truncation; preserves Content-Length on non-chunked, drops the terminator on chunked
Payload corruptionRandom bytes, bit-flips, truncation
Rate limitingGlobal, per-IP, per-endpoint with burst
Traffic shapingBandwidth throttle, packet loss, max connections

Every fault path can be gated on a per-request matcher (source IP / CIDR, header, body size, Transfer-Encoding: chunked).

Quick start

Enable from the CLI

mockforge serve --chaos --chaos-scenario service_instability

service_instability is one of five predefined scenarios. The others are network_degradation, cascading_failure, peak_traffic, slow_backend.

Enable from a config profile

profiles:
  flaky:
    observability:
      chaos:
        enabled: true
        latency:
          enabled: true
          fixed_delay_ms: 250
          jitter_percent: 20
          probability: 0.5
        fault_injection:
          enabled: true
          http_errors: [500, 503]
          http_error_probability: 0.1

Run with mockforge serve --profile flaky.

Recipes: varied 5xx and slow responses

These are the patterns most teams reach for first when exercising client timeout / retry behaviour. Each recipe is copy-pasteable; tune the probabilities to your spec.

Mix of 4xx and 5xx statuses across the whole spec

Global error injection via mockforge serve --chaos. --chaos-http-errors takes a comma-separated list; the injector picks one at the configured probability:

mockforge serve --spec api.yaml --http-port 3000 \
  --chaos --chaos-http-errors 500,502,503,504,429,408 \
  --chaos-http-error-probability 0.10

0.10 means roughly 10% of matching requests get a chaos-status response. The remaining 90% flow through your spec unchanged. Mix 4xx and 5xx as needed: clients should retry-with-backoff on 503/429/504/502 but treat 500/400/422 as terminal.

Slow backend (every request hangs N ms)

Useful for exercising the client’s request-level timeout. Sleeps before the upstream handler runs, so the client experiences a true server-side hang followed by a normal 2xx (or the configured status).

mockforge serve --spec api.yaml --http-port 3000 \
  --chaos --chaos-latency-ms 2000 --chaos-latency-probability 1.0

Pair with --chaos-latency-range 500-5000 to randomise:

mockforge serve --spec api.yaml --http-port 3000 \
  --chaos --chaos-latency-range 500-5000 --chaos-latency-probability 0.30

Real timeout (server hangs, returns 504)

Different from a slow response: this fires when you want the server to report timeout, not just go slow. Configure via the YAML chaos profile:

fault_injection:
  enabled: true
  timeout_errors: true
  timeout_ms: 30000             # 30 s sleep then 504 Gateway Timeout
  timeout_probability: 0.05     # 5% of matching requests

Run with mockforge serve --spec api.yaml --config chaos.yaml.

Per-endpoint chaos (slow this route, error that one)

Global flags hit every route equally. To exercise one endpoint’s timeout while keeping the rest healthy, use per-route chaos:

# routes-with-chaos.yaml
routes:
  - path: /api/slow-report
    method: GET
    response:
      status: 200
      body: { ok: true }
    latency:
      enabled: true
      probability: 1.0
      fixed_delay_ms: 8000        # always hang 8s on this route
  - path: /api/flaky-write
    method: POST
    response:
      status: 201
      body: { id: 1 }
    fault_injection:
      enabled: true
      probability: 0.25           # 25% of POSTs to this route fail
      fault_types:
        - type: http_error
          status_code: 503
          message: "Backend warming up"
        - type: http_error
          status_code: 504
        - type: http_error
          status_code: 429

Mockforge picks one fault_types entry uniformly when the probability fires, so a list of three statuses gives you ~equal weight across the three. Add more entries to bias toward a status (entries are picked uniformly, so two 503 entries plus one 504 entry gives 2:1 odds).

latency.distribution also supports normal { mean_ms, std_dev_ms } and exponential { lambda } for non-uniform spreads — handy when you want “P95 = 8s but a long tail.”

Exercise client retry / backoff behaviour

Combine the two above. The pattern: ~30% of requests get a transient status (503 / 504 / 429), the rest succeed. A well-written client with exponential backoff should eventually succeed on retries; a buggy client either gives up immediately or hammers the server flat.

fault_injection:
  enabled: true
  http_errors: true
  http_error_codes: [503, 504, 429]
  http_error_probability: 0.30
  latency_ms: 250                 # mild latency baseline
  latency_probability: 1.0

Verify what fired

The chaos config exposes counters at GET /api/chaos/status (when admin is enabled). The TUI Chaos screen also surfaces real-time injection counts. Use these to confirm your bench / test client actually saw the intended faults rather than guessing from the response log.

Per-request fault matchers

By default, fault probabilities apply to every request. Add a request_matcher to gate fault injection on properties of the incoming request — useful for targeting specific clients, headers, body sizes, or chunked-encoded traffic without affecting baseline traffic.

fault_injection:
  enabled: true
  http_errors: [503]
  http_error_probability: 0.5     # 50% of *matching* requests get 503
  request_matcher:
    source_ips:
      - "10.0.0.0/8"              # CIDR range; bare IP works too
      - "192.168.1.42"
    headers:
      - name: "x-test"            # case-insensitive
        value: "yes"              # exact value; omit `value` for presence-only
    min_body_size_bytes: 1048576  # only requests with body >= 1 MB
    max_body_size_bytes: 10485760 # AND <= 10 MB (omit either side)
    chunked_only: true            # only Transfer-Encoding: chunked requests

Semantics: AND across fields, OR within a list. Empty matcher matches every request (preserves prior behavior). Applies to all five fault paths (HTTP errors, timeouts, partial responses, payload corruption, connection errors).

TCP-level connection errors

The connection_error_kind knob picks the wire-level behavior:

KindWhat clients see
http_503 (default)HTTP 503 on a healthy connection — application-layer only
tcp_resetTCP RST sent at accept time. Clients see ECONNRESET.
tcp_closeTCP FIN at accept time. Clients see EOF before any HTTP response.
fault_injection:
  enabled: true
  connection_errors: true
  connection_error_probability: 0.05
  connection_error_kind: tcp_reset    # http_503 | tcp_reset | tcp_close

The TCP-level kinds (tcp_reset, tcp_close) wrap the listener with a chaos accept loop, so the fault is per-connection (every request that would have pipelined onto that socket is affected). The wrapper installs automatically when chaos is enabled and the kind is not http_503. Plain HTTP only — TLS path doesn’t yet support TCP-level injection.

Timeouts and partial responses

When timeout_errors: true fires, MockForge sleeps for timeout_ms and then returns 504 Gateway Timeout. The sleep happens before the upstream handler runs, so the client experiences a true server-side hang followed by a 504. Applies uniformly to chunked and non-chunked requests.

When partial_responses: true fires, MockForge truncates the response body:

  • Non-chunked response — preserves the original Content-Length header, so clients perceive an unexpected EOF (they expect N bytes, receive fewer).
  • Chunked response — cuts before the terminating chunk, surfacing as a real protocol violation (IncompleteMessage / ChunkedDecoderError in most HTTP clients).
fault_injection:
  enabled: true
  timeout_errors: true
  timeout_ms: 5000
  timeout_probability: 0.05      # 5% of matching requests hang then 504
  partial_responses: true
  partial_response_probability: 0.05  # 5% get a truncated body

Predefined scenarios

ScenarioProfile
network_degradationHigh latency + packet loss
service_instabilityRandom 5xx errors + timeouts
cascading_failureCombined latency, errors, connection drops, rate limits
peak_trafficAggressive rate limiting (per-endpoint)
slow_backendConsistent 2 s latency on every request
mockforge serve --chaos --chaos-scenario cascading_failure

You can also start, stop, and combine scenarios at runtime via the management API (POST /api/chaos/scenarios/{name}, DELETE /api/chaos/scenarios/{name}). See the reference doc for the full API surface.

Hot-reload

The chaos config is read on every request. Update it via PUT /api/chaos/config and changes apply immediately to subsequent requests — no restart needed.

Observability while testing

When chaos is on, you usually want to watch what’s happening:

  • TUI dashboard (in mockforge-tui): shows current and lifetime peak CPU, memory, and error rate. The error-rate peak is especially useful for multi-hour soak tests where you might miss a spike.
  • CSV metrics log: set MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge.csv to append timestamp,cpu_pct,mem_mb,total_reqs,err_rate every 10 s. Survives restarts; chartable in Grafana / spreadsheets / anything.
  • Prometheus metrics: expose /metrics and scrape with your usual observability stack (mockforge serve --metrics --metrics-port 9090).

Pairing with load testing

Chaos is most useful when you’re driving real traffic at the server. Combine with mockforge bench to generate that traffic:

# Terminal 1 — server with chaos
mockforge serve --spec api.yaml --chaos --chaos-scenario service_instability

# Terminal 2 — drive load
mockforge bench --spec api.yaml --target http://localhost:3000 \
  --vus 50 --duration 5m

For chunked-encoding traffic specifically (e.g. to exercise the chunked_only: true matcher), use the native generator:

mockforge bench-chunked \
  --target http://localhost:3000/upload \
  --concurrency 10 --duration 60 \
  --total-size-bytes 10485760

Where to go next

Rate Limiting & Traffic Shaping

Rate limiting and traffic shaping live in the chaos engine but they’re useful well beyond chaos scenarios. This chapter covers them on their own because most teams reach for them outside of fault injection — to rehearse client-side backoff, throttle local dev environments, or simulate flaky backhaul during integration tests.

Rate Limiting

Cap the request rate at the HTTP layer. Three scopes you can combine:

ScopeUse case
Global“Cap everything at 100 RPS” — load shedding
Per-IP“Each client gets 10 RPS” — abuse mitigation
Per-endpoint“/login gets 5 RPS” — per-route policy

YAML config:

observability:
  chaos:
    enabled: true
    rate_limit:
      enabled: true
      requests_per_second: 100        # token-bucket refill rate
      burst_size: 10                  # additional tokens for short spikes
      per_ip: true                    # token bucket per source IP
      per_endpoint: false             # token bucket per (method, path)

Quick CLI form:

mockforge serve --spec api.yaml --chaos --chaos-rate-limit 100

Rejected requests return 429 Too Many Requests with body Rate limit exceeded. Counts as a chaos_rate_limit_violations_total metric labeled by scope (global / per_ip / per_endpoint) so dashboards can distinguish.

Disabling for trusted clients

# CLI flag
mockforge serve --spec api.yaml --no-rate-limit

# Or env var (preferred for SDK / Docker / k8s setups)
MOCKFORGE_RATE_LIMIT_ENABLED=false mockforge serve --spec api.yaml

For a related case where requests still hit the limit middleware but get exempted, see the per-request matchers in Chaos Engineering — you can scope rate limits to only requests with certain headers or source IPs.

Burst behavior

Rate limiting uses token-bucket semantics, not a hard request-per-second cap:

  • requests_per_second: 100, burst_size: 10 allows 110 requests in the first second (refill + initial burst), then 100 RPS sustained.
  • Use a small burst (e.g. 10–20% of RPS) for “smooth client traffic with occasional spikes.” Use a large burst (e.g. 2× RPS) for “I want to observe what happens when traffic spikes briefly.”

Traffic Shaping

Sub-application-layer constraints. Rate limiting throttles requests; traffic shaping throttles bytes and connections.

observability:
  chaos:
    enabled: true
    traffic_shaping:
      enabled: true
      bandwidth_limit_bps: 1000000     # 1 MB/s, 0 = unlimited
      packet_loss_percent: 2.0         # randomly drop 2% of "packets"
      max_connections: 100             # reject when accept queue > 100
      connection_timeout_ms: 30000     # drop idle connections after 30s

Bandwidth throttling

Caps bytes/sec going through the HTTP layer. Useful for:

  • Simulating slow clients (3G, dial-up, satellite).
  • Pairing with mockforge bench --duration 60 to see how the client handles low-bandwidth conditions.
  • Stress-testing buffer / backpressure logic.

CLI:

mockforge serve --spec api.yaml --chaos --chaos-bandwidth-limit 100000

(100 KB/s.)

Packet loss

Randomly returns 408 Request Timeout for the configured percentage of requests. Not real packet loss at the network layer — that requires tc or iptables. The HTTP-layer simulation is enough to test client-side retry / timeout logic in most cases.

mockforge serve --spec api.yaml --chaos --chaos-packet-loss 5

Connection limits

Caps the number of concurrent connections the listener accepts. New connections beyond max_connections get rejected with 503 Service Unavailable. Useful for testing connection-pool exhaustion in clients.

Predefined network profiles

For common real-world conditions, MockForge ships built-in network profiles that combine latency + bandwidth + connection-error rates:

ProfileLatencyBandwidthNotes
slow_3g400 ms400 KB/s+ 1% packet loss
fast_3g150 ms1.5 MB/s+ 0.5% packet loss
flaky_wifi50 msunlimited+ 5% packet loss + 3% disconnects
cable20 ms10 MB/sclean
dialup2 s50 KB/s+ 2% packet loss
mockforge serve --spec api.yaml --chaos-profile slow_3g

Or list and apply via the management API:

curl http://localhost:3000/api/chaos/profiles            # list
curl -X POST http://localhost:3000/api/chaos/profiles/slow_3g/apply

Example: rehearse client backoff

Question you want to answer: does my client handle 429s with exponential backoff?

# Server: 10 RPS cap, return 429 above that
mockforge serve --spec api.yaml --chaos --chaos-rate-limit 10

# Drive 50 RPS at it
mockforge bench --spec api.yaml --target http://localhost:3000 \
  --vus 50 --duration 30 --scenario constant

Watch the bench output for http_req_failed rate. A correctly-implemented client with backoff will show error rate climbing initially then settling near 80% (40 RPS rejected). A client without backoff will show error rate flat at ~80% for the whole run.

Example: low-bandwidth soak

mockforge serve --spec api.yaml \
  --chaos --chaos-bandwidth-limit 100000 \
  --chaos --chaos-packet-loss 1.0 \
  --metrics --metrics-port 9090

mockforge bench --spec api.yaml --target http://localhost:3000 \
  --vus 5 --duration 1h --scenario soak

Now scrape Prometheus / watch mockforge-tui for memory growth — slow clients tend to surface buffering bugs.

Where to go next

Observability & Metrics

When MockForge is sitting in front of real client traffic — load tests, soak tests, integration test suites running for hours — you usually need three things:

  1. Live numbers. What’s the server doing right now?
  2. Structured metrics. Pull into Grafana / Datadog / your dashboarding tool.
  3. A persistent record. When you come back tomorrow, what was the worst case overnight?

MockForge ships all three. Pick whichever fits your workflow.

SurfaceSource of truthWhen to use
TUI dashboardIn-processLocal dev, quick eyeballing
Admin UI Analytics pageIn-processBrowser-based per-server traffic charts (request volume, p95/p99 latency, error rate, endpoint heatmap) — self-hosted only
Prometheus /metricsIn-process Prometheus registryYou already run Prometheus / Grafana
OpenTelemetry / OTLPOTLP exporter → collectorYou already run Jaeger / Tempo / Honeycomb
CSV metrics logMOCKFORGE_METRICS_LOG_FILE env varMulti-day soak tests; want a flat file

These aren’t mutually exclusive — turn on whichever combination fits.

Cloud users: the Admin UI Analytics page reads in-process counters from the local mock server and is hidden in cloud mode. For hosted-mock analytics see the Analytics Dashboard (pillar-level usage) and the in-app Cloud Traces view (individual requests).

TUI dashboard

mockforge-tui

Live dashboard in the terminal. Auto-refreshes every 2 s. Shows current and lifetime peak CPU / memory / error rate next to the live numbers, so you can leave it open during a soak test and glance at it later to see what the worst case was.

For the full panel layout and keybindings, see the TUI Dashboard chapter.

Prometheus metrics

Enable the metrics endpoint when starting the server:

mockforge serve --spec api.yaml --metrics --metrics-port 9090

Scrape http://localhost:9090/metrics from Prometheus. Default port is 9090; change with --metrics-port or in config:

observability:
  metrics:
    enabled: true
    port: 9090
    path: "/metrics"

What gets exported

Mock server core:

  • http_requests_total (counter, labels: method, path, status)
  • http_request_duration_seconds (histogram, labels: method, path)
  • active_connections (gauge, labels: protocol)
  • mock_response_generations_total (counter, labels: template_type)

Chaos engine (when --chaos is on):

  • chaos_faults_injected_total (counter, labels: kind, endpoint) — kind ∈ http_error, connection_error, timeout, partial_response, payload_corruption
  • chaos_latency_injected_seconds (histogram, labels: endpoint)
  • chaos_rate_limit_violations_total (counter, labels: kind) — kind ∈ global, per_ip, per_endpoint
  • chaos_circuit_breaker_state (gauge: 0 closed, 1 half-open, 2 open)
  • chaos_bulkhead_concurrent (gauge)
  • chaos_scenarios_total (counter, labels: scenario, event)

Resilience features:

  • chaos_orchestration_step_duration_seconds (histogram)
  • chaos_orchestration_executions_total (counter, labels: status)
  • chaos_assertion_results_total (counter, labels: result)

Grafana starter dashboard

A starter Grafana dashboard JSON ships in the repo at book/src/assets/mockforge-starter.json (when present in your install). Import via Grafana Dashboards → Import and pick your Prometheus data source. The dashboard graphs request rate, p50/p95/p99 latency, error rate, and per-fault chaos counters by default.

OpenTelemetry / OTLP

For distributed tracing, MockForge can export OTLP spans to any compatible collector (Jaeger, Tempo, Honeycomb, Datadog, etc.).

MOCKFORGE_OTLP_ENDPOINT=http://otel-collector:4317 \
MOCKFORGE_OTLP_SERVICE_NAME=mockforge \
MOCKFORGE_OTLP_SAMPLING_RATE=1.0 \
  mockforge serve --spec api.yaml --tracing

YAML form:

observability:
  tracing:
    enabled: true
    exporter: otlp                    # otlp | jaeger
    otlp:
      endpoint: "http://otel-collector:4317"
      service_name: "mockforge"
      sampling_rate: 1.0              # 0.0–1.0, 1.0 = trace every request
    # Or, for legacy Jaeger native:
    jaeger:
      endpoint: "http://jaeger:14268/api/traces"

What gets traced

Each incoming HTTP / gRPC / WebSocket request opens a top-level span with attributes: http.method, http.route, http.status_code, mockforge.protocol. Inner spans cover:

  • OpenAPI route matching
  • Template expansion
  • Plugin invocation (one span per plugin call)
  • Chaos middleware decisions (latency injected, faults injected)
  • Upstream proxy calls (if you’re running in proxy mode)

Sampling is head-based at sampling_rate. For chaos / load testing where you only care about the long tail, set 0.01 and have your collector upweight on error=true spans.

Pairing with metrics

OTLP and Prometheus aren’t either/or. A common pattern:

  • Prometheus for rate / error / duration RED metrics (cheap, always on).
  • OTLP for individual request traces (sampled, on for investigations).

Both can run simultaneously. Run a combined demo with:

MOCKFORGE_OTLP_ENDPOINT=http://localhost:4317 \
  mockforge serve --spec api.yaml \
    --metrics --metrics-port 9090 \
    --tracing

CSV metrics log (multi-day soak)

For long-running test scenarios where you want a flat record that survives a server restart and chart in any tool:

MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge-metrics.csv \
  mockforge serve --spec api.yaml --admin

Appends one row every 10 s:

timestamp,cpu_pct,mem_mb,total_reqs,err_rate
2026-05-02T12:00:00Z,3.45,412,12345,0.012
2026-05-02T12:00:10Z,4.12,415,12567,0.013

Parse with anything (pandas, awk, Grafana CSV data source, Excel). Header is written when the file is empty/new; existing files just get appended to, so multiple runs accumulate.

Combining all four

For a real chaos / load test you usually want everything at once:

# Server: chaos + metrics + tracing + CSV log
MOCKFORGE_OTLP_ENDPOINT=http://otel-collector:4317 \
MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge-soak.csv \
  mockforge serve \
    --spec api.yaml \
    --chaos --chaos-scenario service_instability \
    --metrics --metrics-port 9090 \
    --tracing \
    --admin --admin-port 9080

# Watch live in one terminal
mockforge-tui

# Drive load in another
mockforge bench --spec api.yaml --target http://localhost:3000 \
  --duration 6h --vus 50

Now you have:

  • Live: TUI shows current state + peak readouts.
  • Streaming: Prometheus /metrics for Grafana panels.
  • Sampled deep-dives: OTLP traces for individual problem requests.
  • Persistent: CSV log survives the run for next-day analysis.

Where to go next

TUI Dashboard

mockforge-tui is a terminal dashboard (a separate binary in the mockforge-tui crate) you point at a running MockForge admin server. It’s the fastest way to see what’s happening: live metrics, recent requests, chaos events, fixture inventory, error logs — all on one screen, no browser.

# Start the server with admin enabled
mockforge serve --spec api.yaml --admin --admin-port 9080

# In another terminal
mockforge-tui

The TUI talks to the admin server’s HTTP API (default http://localhost:9080); set the --admin-url flag if it’s elsewhere.

KeyAction
Tab / Shift-TabNext / previous panel
1–9, 0Jump to panel by number
rForce refresh the current panel
q / Ctrl-CQuit
↑ ↓ j kScroll within a panel
EnterDrill into the highlighted row (where applicable)

Panels auto-refresh every 2 s; r forces an immediate fetch.

Dashboard panel (1)

Four quadrants:

┌─ Server Status ─────────────────┬─ System Metrics ─────────────────┐
│ ● HTTP    127.0.0.1:3000        │ CPU: 18% (peak 67%)              │
│ ● WS      127.0.0.1:3001        │ Mem: 412 MB (peak 891 MB)        │
│ ● Admin   127.0.0.1:9080        │ Threads: 8  Routes: 25  ...      │
│                                 │                                  │
├─ Request Stats ─────────────────┼─ Recent Logs ────────────────────┤
│ Total: 12.5K  Err Rate: 0.4%    │ 14:23:01 GET    /api/users  200  │
│ (peak 12.3%)                    │ 14:23:01 POST   /api/orders 201  │
│ Avg RT: 34ms                    │ 14:23:00 GET    /api/users  200  │
│ ┃▆█▇▅▆█▇▅▆█▇▅▆█▇▅▆█▇▅           │ ...                              │
└─────────────────────────────────┴──────────────────────────────────┘

What each cell shows

Server Status — one row per protocol you’ve enabled. ● = up, ○ = down. Address is what the listener actually bound to (so you see the real port when you started with --http-port 0).

System Metrics — current value + lifetime peak (since server start, or since the last reset_metric_peaks() API call):

  • CPU: <current>% (peak <peak>%) — process CPU usage. Peak helps you catch transient spikes during multi-hour soak tests.
  • Mem: <current> MB (peak <peak> MB) — process RSS. Peak is the important number for memory-leak hunting.
  • Threads: N — count of OS threads in the runtime.
  • Routes: N — registered HTTP routes.
  • Fixtures: N — fixture files discovered.

Request Stats — total requests served, error rate (5xx + 4xx / total), peak error rate, average response time, and a sparkline of request rate over the last 60 ticks (~2 minutes).

Recent Logs — last 10 requests (or however many fit), newest at top. Color-coded by HTTP method and status code.

Resetting peaks

Peaks accumulate from server start. To reset at the beginning of a new test run without restarting the server, hit the admin API:

curl -X POST http://localhost:9080/api/admin/metrics/reset-peaks

Or reset programmatically via the SDK.

Other panels

PanelWhat it shows
Routes (2)Every HTTP route registered, with hit count and last-request timestamp
Fixtures (3)Fixture files on disk, sizes, last-modified
Logs (4)Full request log with filter/search
Metrics (5)Detailed numeric metrics (response-time distribution, status code histogram)
Chaos (6)Live chaos engine state — current scenario, fault counters per kind, request matchers
Plugins (7)Loaded plugins, their status, recent invocations
Recorder (8)Traffic recordings — start/stop, file sizes, replay status
Health (9)Health checks, circuit breaker / bulkhead state, dependency status

Each is also reachable via the admin web UI at http://localhost:9080; the TUI is the same data over the same API, just rendered for the terminal.

When to use the TUI vs admin web UI

Use TUI when…Use admin UI when…
You’re SSH’d to a remote boxYou want to edit fixtures interactively
You want to leave it open during a soak testYou’re sharing a screenshot
Browser is too heavyYou need the visual config builder
You want everything on one screenYou’re walking someone through a feature

CSV log alongside

The TUI peak metrics are in-memory and reset on server restart. For a permanent record across restarts, set:

MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge.csv mockforge serve ...

The same numbers the TUI displays (CPU%, memory MB, total requests, error rate) get appended every 10 s to the CSV file. See the Observability chapter for details.

Troubleshooting

“Failed to fetch dashboard” — the admin server isn’t running, or it’s on a different host/port. Use --admin-url http://host:port and retry. Make sure you started mockforge serve with --admin.

Metrics show all zeroes — system monitoring runs in a background task that takes ~10 s to collect its first sample after server start. Wait a moment and hit r to refresh.

TUI feels sluggish — the 2 s refresh fetches a lot. Switch to the admin web UI for low-traffic panels (Plugins, Fixtures); the TUI is most useful for high-velocity ones (Dashboard, Logs, Chaos, Metrics).

Where to go next

Cloud Workspaces (Collaboration)

Cloud Workspaces is the clearest current path for team-oriented MockForge usage. It combines shared workspace records, cloud sync, and collaborator management so teams can keep mocks aligned across local development and shared environments.

Overview

Cloud Workspaces provides:

  • Cloud authentication via mockforge cloud login
  • Shared workspace records with cloud workspace create/list/info flows
  • Directory linking from a local project to a cloud workspace
  • Cloud sync with status, history, and pending-change checks
  • Team membership management through invite/list/remove commands

Quick Start

Authenticate

# Authenticate with MockForge Cloud
mockforge cloud login

# Check authentication status
mockforge cloud whoami

Create and Inspect a Cloud Workspace

# Create a shared cloud workspace
mockforge cloud workspace create my-workspace --name "My Workspace"

# List cloud workspaces
mockforge cloud workspace list

# Inspect a workspace
mockforge cloud workspace info my-workspace
# Link the current project directory to the cloud workspace
mockforge cloud workspace link . my-workspace

# Start bidirectional sync and watch for changes
mockforge cloud sync start --workspace my-workspace --watch

Core Commands

Authentication and Identity

  • mockforge cloud login
  • mockforge cloud whoami
  • mockforge cloud logout

Cloud Workspace Management

  • mockforge cloud workspace list
  • mockforge cloud workspace create <workspace-id> --name "..."
  • mockforge cloud workspace info <workspace-id>
  • mockforge cloud workspace link <local-path> <cloud-workspace-id>
  • mockforge cloud workspace unlink <local-path>

Team Membership

# Invite a collaborator
mockforge cloud team invite [email protected] \
  --workspace my-workspace \
  --role editor

# List collaborators
mockforge cloud team members --workspace my-workspace

# Remove a collaborator
mockforge cloud team remove [email protected] --workspace my-workspace

Sync Operations

# Show sync status
mockforge cloud sync status --workspace my-workspace

# Show pending changes
mockforge cloud sync pending --workspace my-workspace

# Show sync history
mockforge cloud sync history --workspace my-workspace

Notes on Readiness

  • The cloud workspace and sync commands above are present in the CLI source and are the safest public workflow to document.
  • Other collaboration surfaces exist in the codebase, but some older docs examples referenced command shapes that are not part of the current public CLI.
  • If you are documenting a buyer-facing hosted workflow, prefer the verified cloud and workspace flows above over speculative collaboration examples.

Local Admin Workspaces vs Cloud Workspaces

MockForge also has local admin-oriented workspace commands such as:

  • mockforge workspace list
  • mockforge workspace create <workspace-id> --name "..."
  • mockforge workspace info <workspace-id>

Those are useful for local or self-hosted admin flows, but they are distinct from the cloud collaboration commands documented above.

MockOps Pipelines

Pillars: [Cloud]

MockOps Pipelines are an advanced automation surface for event-driven mock lifecycle orchestration. The underlying pipeline crate and event model exist in the codebase, but this page should be read as an implementation and integration guide, not as a polished end-user CLI workflow.

Readiness note: this feature is better treated as an advanced platform capability than a default buyer path unless you have verified the surrounding deployment, persistence, and triggering model in your own environment.

Overview

MockOps Pipelines enable:

  • Schema Change → Auto-Regenerate SDK: When OpenAPI changes, automatically regenerate client SDKs
  • Scenario Published → Auto-Promote to Test → Notify Teams: Automatically promote scenarios and notify teams
  • Drift Threshold Exceeded → Auto-Generate Git PR: Create PRs with fixes when drift exceeds thresholds

Pipeline Structure

Pipelines are defined in YAML and triggered by events:

name: schema-change-pipeline
definition:
  enabled: true
  triggers:
    - event: schema.changed
      filters:
        workspace_id: "workspace-123"
        schema_type: ["openapi", "protobuf"]
  steps:
    - name: regenerate-sdks
      step_type: regenerate_sdk
      config:
        languages: ["typescript", "python", "rust"]
        workspace_id: "{{workspace_id}}"
    - name: notify-teams
      step_type: notify
      config:
        type: slack
        channels: ["#api-team", "#frontend-team"]
        message: "SDKs regenerated for {{workspace_id}}"

Available Events

Schema Changed

Triggered when OpenAPI/Protobuf schemas are modified:

triggers:
  - event: schema.changed
    filters:
      schema_type: ["openapi", "protobuf"]
      workspace_id: "workspace-123"

Payload:

  • spec_path: Path to schema file
  • schema_type: “openapi” or “protobuf”
  • changes: List of changes (added/removed/modified endpoints)

Scenario Published

Triggered when a new scenario is published:

triggers:
  - event: scenario.published
    filters:
      workspace_id: "workspace-123"

Payload:

  • scenario_id: ID of published scenario
  • scenario_name: Name of scenario
  • version: Scenario version
  • workspace_id: Workspace ID

Drift Threshold Exceeded

Triggered when drift budget threshold is exceeded:

triggers:
  - event: drift.threshold_exceeded

Payload:

  • endpoint: Affected endpoint
  • drift_count: Number of drift incidents
  • threshold: Threshold that was exceeded
  • drift_data: Detailed drift information

Promotion Completed

Triggered when entity promotion completes:

triggers:
  - event: promotion.completed

Payload:

  • promotion_id: Promotion ID
  • entity_type: “scenario”, “persona”, or “config”
  • from_environment: Source environment
  • to_environment: Target environment

Available Steps

Regenerate SDK

Regenerates client SDKs from OpenAPI/Protobuf specs:

steps:
  - name: regenerate-sdks
    step_type: regenerate_sdk
    config:
      spec_path: "{{event.spec_path}}"
      languages: ["typescript", "python", "rust"]
      output_dir: "./generated-sdks"

Config Options:

  • spec_path: Path to OpenAPI/Protobuf spec
  • languages: Array of languages to generate
  • output_dir: Output directory (default: ./generated-sdks)

Auto-Promote

Automatically promotes entities between environments:

steps:
  - name: auto-promote
    step_type: auto_promote
    config:
      entity_type: scenario
      entity_id: "{{event.scenario_id}}"
      from_environment: dev
      to_environment: test

Config Options:

  • entity_type: “scenario”, “persona”, or “config”
  • entity_id: ID of entity to promote
  • from_environment: Source environment
  • to_environment: Target environment
  • comments: Optional promotion comments

Notify

Sends notifications via Slack, email, or webhook:

steps:
  - name: notify-teams
    step_type: notify
    config:
      type: slack
      slack_webhook_url: "https://hooks.slack.com/services/..."
      channels: ["#api-team", "#frontend-team"]
      message: "SDKs regenerated for {{workspace_id}}"

Config Options:

  • type: “slack”, “email”, or “webhook”
  • message: Notification message (supports template variables)
  • slack_webhook_url: Slack webhook URL (for Slack type)
  • channels: Array of channel names (for Slack type)
  • email_to: Array of email addresses (for email type)
  • webhook_url: Webhook URL (for webhook type)

Create PR

Creates Git pull requests:

steps:
  - name: create-pr
    step_type: create_pr
    config:
      repository: "https://github.com/org/repo"
      branch: "main"
      title: "Drift Violation: {{event.endpoint}}"
      body: "Drift count: {{event.drift_count}}, Threshold: {{event.threshold}}"
      files:
        - path: "drift-report.json"
          content: "{{event.drift_data}}"
          operation: create

Config Options:

  • repository: Git repository URL
  • branch: Target branch
  • title: PR title
  • body: PR body (supports template variables)
  • files: Array of files to include in PR

Common Use Cases

1. Auto-Regenerate SDKs on Schema Changes

name: auto-sdk-regeneration
definition:
  enabled: true
  triggers:
    - event: schema.changed
      filters:
        schema_type: openapi
  steps:
    - name: regenerate_sdk
      step_type: regenerate_sdk
      config:
        spec_path: "{{event.spec_path}}"
        languages: ["typescript", "rust", "python"]
        output_dir: "./generated-sdks"

2. Auto-Promote Scenarios to Test

name: auto-promote-to-test
definition:
  enabled: true
  triggers:
    - event: scenario.published
      filters:
        workspace_id: "your-workspace-id"
  steps:
    - name: auto_promote
      step_type: auto_promote
      config:
        entity_type: scenario
        entity_id: "{{event.scenario_id}}"
        from_environment: dev
        to_environment: test
    - name: notify_team
      step_type: notify
      config:
        type: slack
        slack_webhook_url: "https://hooks.slack.com/services/..."
        channels: ["#devops"]
        message: "Scenario {{event.scenario_name}} promoted to test"

3. Create PR on Drift Violations

name: drift-gitops-pr
definition:
  enabled: true
  triggers:
    - event: drift.threshold_exceeded
  steps:
    - name: create_pr
      step_type: create_pr
      config:
        repository: "https://github.com/org/repo"
        branch: "main"
        title: "Drift Violation: {{event.endpoint}}"
        body: "Drift count: {{event.drift_count}}, Threshold: {{event.threshold}}"
        files:
          - path: "drift-report.json"
            content: "{{event.drift_data}}"
            operation: create

Template Variables

Pipeline steps support template variables:

  • {{event.field}}: Access event payload fields
  • {{workspace_id}}: Current workspace ID
  • {{workspace_name}}: Current workspace name
  • {{timestamp}}: Current timestamp

Pipeline Management

There is no mockforge pipelines CLI. Pipelines are managed through the HTTP API, which is mounted on the HTTP server when MockForge is built with the pipelines feature. Pipelines are held in memory.

Create Pipeline

POST /api/v1/pipelines
{
  "name": "my-pipeline",
  "definition": {...},
  "workspace_id": "<workspace-uuid>"
}

List Pipelines

# List all pipelines
GET /api/v1/pipelines

# List pipelines for workspace
GET /api/v1/pipelines?workspace_id=<workspace-uuid>

Enable/Disable Pipeline

# Enable or disable a pipeline
PATCH /api/v1/pipelines/{id}
{
  "enabled": false
}

# Trigger a pipeline manually (request body is a pipeline event)
POST /api/v1/pipelines/{id}/trigger

View Pipeline Executions

# View pipeline executions
GET /api/v1/pipelines/executions?pipeline_id=<pipeline-id>

# View execution details
GET /api/v1/pipelines/executions/{id}

# View pipeline statistics
GET /api/v1/pipelines/{id}/stats

Best Practices

  1. Start Simple: Begin with one-step pipelines
  2. Test Incrementally: Test each step individually
  3. Use Filters: Filter events to avoid unnecessary executions
  4. Monitor Executions: Review execution logs regularly
  5. Version Control: Keep pipeline definitions in Git

Multi-Workspace Federation

Pillars: [Cloud]

Multi-Workspace Federation enables composing multiple mock workspaces into one federated “virtual system” for large organizations with microservices architectures.

Readiness note: treat this page as an architecture and design guide. Federation concepts and supporting code paths exist, but this page should not be read as a verified public CLI workflow unless you have confirmed the exact deployment surface in your environment.

Overview

Federation allows you to:

  • Define Service Boundaries: Map services to workspaces
  • Compose Virtual Systems: Combine multiple workspaces into one system
  • Run System-Wide Scenarios: Define scenarios that span multiple services
  • Control Reality Per Service: Set reality level independently per service

Key Concepts

Service Boundaries

Services represent individual microservices in your architecture:

services:
  - name: auth
    workspace_id: "workspace-auth-123"
    base_path: "/auth"
    reality_level: "real"  # Use real upstream

Federation

A federation is a collection of services that work together:

federation:
  name: "e-commerce-platform"
  services:
    - name: auth
      workspace_id: "workspace-auth-123"
      base_path: "/auth"
      reality_level: "real"
    - name: payments
      workspace_id: "workspace-payments-456"
      base_path: "/payments"
      reality_level: "mock_v3"

Virtual System

The federated system appears as a single unified API:

/api/auth/*          → Auth service (real)
/api/payments/*      → Payments service (mock v3)
/api/inventory/*    → Inventory service (blended)
/api/shipping/*     → Shipping service (chaos-driven)

Service Reality Levels

Each service can have its own reality level:

Real

Use real upstream (no mocking):

services:
  - name: auth
    reality_level: "real"

Use Case: Critical services that must be real (auth, payment processing).

Mock V3

Use mock with reality level 3:

services:
  - name: payments
    reality_level: "mock_v3"

Use Case: Services under development or testing.

Blended

Mix of mock and real data:

services:
  - name: inventory
    reality_level: "blended"
    blend_ratio: 0.5  # 50% real, 50% mock

Use Case: Gradual migration from mock to real.

Chaos-Driven

Chaos testing mode:

services:
  - name: shipping
    reality_level: "chaos_driven"

Use Case: Resilience testing, chaos engineering.

Configuration

Define Federation

# federation.yaml
federation:
  name: "e-commerce-platform"
  description: "Federated e-commerce system"
  services:
    - name: auth
      workspace_id: "workspace-auth-123"
      base_path: "/auth"
      reality_level: "real"
      config:
        upstream_url: "https://auth.example.com"
    
    - name: payments
      workspace_id: "workspace-payments-456"
      base_path: "/payments"
      reality_level: "mock_v3"
      config:
        reality_level: 3
        chaos_enabled: false
    
    - name: inventory
      workspace_id: "workspace-inventory-789"
      base_path: "/inventory"
      reality_level: "blended"
      config:
        blend_ratio: 0.5
        reality_continuum:
          enabled: true
          default_ratio: 0.5
    
    - name: shipping
      workspace_id: "workspace-shipping-012"
      base_path: "/shipping"
      reality_level: "chaos_driven"
      config:
        chaos:
          enabled: true
          error_rate: 0.1
          latency_spike_probability: 0.2

Service Dependencies

Define dependencies between services:

services:
  - name: orders
    workspace_id: "workspace-orders-123"
    base_path: "/orders"
    dependencies:
      - payments
      - inventory
      - shipping

Dependencies are used for:

  • System-wide scenario ordering
  • Service startup coordination
  • Dependency graph visualization

System-Wide Scenarios

Define scenarios that span multiple services:

system_scenarios:
  - name: end-to-end-checkout
    description: "Complete checkout flow across services"
    steps:
      - service: auth
        endpoint: POST /auth/login
        extract:
          token: "body.token"
      
      - service: inventory
        endpoint: GET /inventory/products/{product_id}
        headers:
          Authorization: "Bearer {{token}}"
        extract:
          product: "body"
      
      - service: payments
        endpoint: POST /payments/charge
        headers:
          Authorization: "Bearer {{token}}"
        body:
          amount: "{{product.price}}"
        extract:
          payment_id: "body.id"
      
      - service: orders
        endpoint: POST /orders
        headers:
          Authorization: "Bearer {{token}}"
        body:
          product_id: "{{product.id}}"
          payment_id: "{{payment_id}}"

Routing

The federation router routes requests to appropriate services:

Path-Based Routing

Requests are routed based on path prefixes:

GET /auth/users/123     → Auth service
GET /payments/charge    → Payments service
GET /inventory/products → Inventory service

Longest Match

The router uses longest match for path matching:

/api/v1/payments/charge → Payments service (longer match)
/api/v1/payments         → Payments service
/api/v1                 → Default service

Current Surface

The safest way to use this page today is as:

  • A model for how to partition workspaces by service boundary
  • A planning document for composing larger multi-service test environments
  • A reference when evaluating whether your deployment should expose federation-aware routing or peer views

The codebase includes federation-oriented surfaces, including peer-oriented views in the TUI and related handlers, but the command examples that used to appear here were more productized than the currently verified public workflow.

Real-World Example

E-Commerce Platform

federation:
  name: "e-commerce-platform"
  services:
    # Auth - Always real (critical service)
    - name: auth
      workspace_id: "workspace-auth"
      base_path: "/auth"
      reality_level: "real"
    
    # Payments - Mock v3 (under development)
    - name: payments
      workspace_id: "workspace-payments"
      base_path: "/payments"
      reality_level: "mock_v3"
    
    # Inventory - Blended (gradual migration)
    - name: inventory
      workspace_id: "workspace-inventory"
      base_path: "/inventory"
      reality_level: "blended"
      config:
        blend_ratio: 0.3  # 30% real, 70% mock
    
    # Shipping - Chaos-driven (resilience testing)
    - name: shipping
      workspace_id: "workspace-shipping"
      base_path: "/shipping"
      reality_level: "chaos_driven"

Result: Single unified API with different reality levels per service.

Best Practices

  1. Start Small: Begin with 2-3 services
  2. Define Boundaries: Clearly define service boundaries
  3. Use Dependencies: Document service dependencies
  4. Test Scenarios: Create system-wide test scenarios
  5. Monitor Routing: Monitor routing performance

Analytics Dashboard

Pillars: [Cloud]

The Analytics Dashboard provides leadership insight into coverage, risk, and usage. It shows which scenarios are used most, what personas are hit by CI, which endpoints are under-tested, which mocks have stale reality levels, and what percentage of mocks are drifting from real data.

Scope. This dashboard surfaces pillar-level usage (Reality / Chaos / Contracts / etc.) at workspace and org scope. Request-traffic analytics — per-server request volume, p95/p99 latency, error rate, and endpoint heatmaps — is a self-hosted feature exposed through the local /analytics page. In cloud mode use this dashboard plus the in-app Cloud Traces view for individual-request inspection.

Deployment note: the analytics routes documented here exist in the codebase, but they depend on the analytics database and the UI/router layer being enabled in your environment. Treat this as a real API surface with deployment prerequisites, not a guaranteed default on every MockForge install.

Overview

The Analytics Dashboard gives you:

  • Scenario Usage Heatmaps: Which scenarios are used most, usage patterns over time
  • Persona CI Hit Tracking: Which personas are hit by CI, persona usage frequency
  • Endpoint Coverage Analysis: Which endpoints are under-tested, test coverage per endpoint
  • Reality Level Staleness: Which mocks have stale reality levels, recommendations for updates
  • Drift Percentage Tracking: What percentage of mocks are drifting from real data, drift trends

Scenario Usage Heatmaps

Overview

Visualize which scenarios are used most frequently:

Scenario                    Usage Count    Last Used
─────────────────────────────────────────────────────
checkout-success           1,234          2025-01-27
payment-failure            892           2025-01-27
cart-abandonment           567           2025-01-26
user-signup                445           2025-01-25

Usage Patterns

View usage patterns over time:

  • Peak usage times
  • Usage trends (increasing/decreasing)
  • Seasonal patterns

Access

# Get scenario usage metrics
GET /api/v2/analytics/scenarios/usage?workspace_id=workspace-123&time_range=30d

Persona CI Hit Tracking

Overview

Track which personas are used in CI/CD pipelines:

Persona                    CI Hits    Last Hit
───────────────────────────────────────────────
premium-customer           234        2025-01-27
fraud-suspect              156        2025-01-27
new-user                   89        2025-01-26
churned-user               45        2025-01-25

Insights

  • Coverage Gaps: Personas not hit by CI
  • Usage Frequency: How often personas are used
  • CI Integration: Which CI systems use which personas

Access

# Get persona CI hits
GET /api/v2/analytics/personas/ci-hits?workspace_id=workspace-123

Endpoint Coverage Analysis

Overview

Identify which endpoints are under-tested:

Endpoint                    Test Count    Last Tested    Coverage
─────────────────────────────────────────────────────────────────
GET /api/users/{id}         45           2025-01-27     100%
POST /api/orders            23           2025-01-26     85%
GET /api/products           12           2025-01-25     60%  ⚠️
DELETE /api/users/{id}      5            2025-01-20     30%  ⚠️

Coverage Metrics

  • Test Count: Number of tests covering endpoint
  • Last Tested: When endpoint was last tested
  • Coverage Percentage: Test coverage score
  • Missing Scenarios: Scenarios that should exist but don’t

Access

# Get endpoint coverage
GET /api/v2/analytics/endpoints/coverage?workspace_id=workspace-123&min_coverage=80

Reality Level Staleness

Overview

Track which mocks have stale reality levels:

Endpoint                    Current Level    Last Updated    Staleness
─────────────────────────────────────────────────────────────────────
GET /api/users/{id}        3               2025-01-15      12 days  ⚠️
POST /api/orders           2               2025-01-20      7 days
GET /api/products          4               2025-01-27      0 days

Recommendations

  • Update Needed: Mocks with stale reality levels
  • Update Priority: Based on usage and importance
  • Update Suggestions: Recommended reality level updates

Access

# Get reality level staleness
GET /api/v2/analytics/reality-levels/staleness?workspace_id=workspace-123&max_staleness_days=30

Drift Percentage Tracking

Overview

Track what percentage of mocks are drifting from real data:

Metric                      Value    Trend
───────────────────────────────────────────
Total Mocks                150      ─
Drifting Mocks             45       ↑
Drift Percentage           30%      ↑
High-Drift Mocks           12       ↑

View drift trends over time:

  • Increasing drift (mocks diverging from real)
  • Decreasing drift (mocks converging with real)
  • Stable drift (consistent divergence)

Access

# Get drift percentage
GET /api/v2/analytics/drift/percentage?workspace_id=workspace-123

Dashboard Views

Overview Dashboard

High-level metrics:

  • Total scenarios, personas, endpoints
  • Overall coverage percentage
  • Average reality level staleness
  • Overall drift percentage

Detailed Views

Drill down into specific areas:

  • Scenario usage details
  • Persona usage breakdown
  • Endpoint coverage details
  • Reality level analysis
  • Drift analysis

Configuration

Enable Analytics

# mockforge.yaml
analytics:
  enabled: true
  collection_interval: 60  # seconds
  retention_days: 90

Coverage Thresholds

analytics:
  coverage:
    min_coverage_percentage: 80
    alert_on_low_coverage: true

Staleness Thresholds

analytics:
  staleness:
    max_staleness_days: 30
    alert_on_stale: true

Best Practices

  1. Review Regularly: Check dashboard weekly/monthly
  2. Set Thresholds: Configure coverage and staleness thresholds
  3. Act on Insights: Use insights to improve testing and mocks
  4. Track Trends: Monitor trends over time
  5. Share with Team: Share insights with development teams

Advanced Features

MockForge includes a comprehensive set of advanced features that enable sophisticated mocking scenarios, intelligent behavior simulation, and production-like testing environments. This section provides an overview of all advanced features with links to detailed documentation.

Overview

MockForge’s advanced features are organized into several categories:

  • Simulation & State Management: Virtual Backend Reality (VBR), Temporal Simulation, Scenario State Machines, World State Engine
  • Intelligence & Automation: MockAI, Generative Schema Mode, AI Contract Diff, API Architecture Critique, System Generation, Behavioral Simulation
  • Chaos & Realism: Chaos Lab, Reality Slider, Reality Profiles Marketplace, Behavioral Economics Engine, Performance Mode
  • Collaboration & Cloud: Cloud Workspaces, Data Scenario Marketplace, MockOps Pipelines, Federation, Analytics Dashboard
  • Developer Experience: ForgeConnect SDK, Zero-Config Mode, Snapshot Diff, Mock-Oriented Development
  • Experimental Features: Deceptive Deploys, Voice + LLM Interface, Reality Continuum, Smart Personas

Simulation & State Management

Virtual Backend Reality (VBR) Engine

The VBR Engine provides a virtual “database” layer that automatically generates CRUD operations from OpenAPI specifications. It supports relationship mapping, data persistence, and state management.

Key Features:

  • Automatic CRUD generation from OpenAPI specs
  • Support for 1:N and N:N relationships
  • Multiple storage backends (JSON, SQLite, in-memory)
  • Data seeding and state snapshots
  • Realistic ID generation

Learn More: VBR Engine Documentation

Temporal Simulation (Time Travel)

Temporal Simulation allows you to control time in your mock environment, enabling time-based data mutations, scheduled events, and time-travel debugging.

Key Features:

  • Virtual clock abstraction
  • Time advancement controls
  • Data mutation rules triggered by time
  • Scheduler for simulated cron events
  • UI controls for time travel

Learn More: Temporal Simulation Documentation

Scenario State Machines 2.0

Advanced state machine system for modeling complex workflows and multi-step scenarios with visual flow editing and conditional transitions.

Key Features:

  • Visual flow editor for state transitions
  • Conditional transitions with if/else logic
  • Reusable sub-scenarios
  • Real-time preview of active state
  • Programmatic state manipulation

Learn More: Scenario State Machines Documentation

Intelligence & Automation

MockAI (Intelligent Mocking)

MockAI uses artificial intelligence to generate contextually appropriate, realistic API responses. It learns from OpenAPI specifications and example payloads.

Key Features:

  • Trainable rule engine from examples or schema
  • Context-aware conditional logic generation
  • LLM-based dynamic response option
  • Automatic fake data consistency
  • Realistic validation error simulation

Learn More: MockAI Documentation

Generative Schema Mode

Generate complete API ecosystems from JSON payloads, automatically creating routes, schemas, and entity relationships.

Key Features:

  • Complete “JSON → entire API ecosystem” generation
  • Auto-route generation with realistic CRUD mapping
  • One-click environment creation from JSON payloads
  • Entity relation inference
  • Schema merging from multiple examples

Learn More: Generative Schema Mode Documentation

AI Contract Diff

Automatically detect and analyze differences between API contracts and live requests, providing contextual recommendations for mismatches.

Key Features:

  • Contract diff analysis between schema and live requests
  • Contextual recommendations for mismatches
  • Inline schema correction proposals
  • CI/CD integration (contract verification step)
  • Dashboard visualization of mismatches

Learn More: AI Contract Diff Documentation

API Architecture Critique

LLM-powered analysis of API schemas to detect anti-patterns, redundancies, naming issues, emotional tone problems, and restructuring recommendations.

Key Features:

  • Anti-pattern detection
  • Redundancy detection
  • Naming quality assessment
  • Emotional tone analysis
  • Restructuring recommendations

Learn More: API Architecture Critique Documentation

System Generation

Generate complete backend systems from natural language descriptions, including endpoints, personas, lifecycles, WebSocket topics, and more.

Key Features:

  • 20-30 REST endpoints from description
  • 4-5 personas based on roles
  • 6-10 lifecycle states
  • WebSocket topics
  • Full OpenAPI spec
  • CI pipeline templates

Learn More: System Generation Documentation

Behavioral Simulation

Model users as narrative agents that react to app state, form intentions, respond to errors, and trigger multi-step interactions.

Key Features:

  • Narrative agents
  • React to app state
  • Form intentions (shop, browse, buy, abandon)
  • Respond to errors
  • Multi-step interactions

Learn More: Behavioral Simulation Documentation

Chaos & Realism

Chaos Lab

Interactive network condition simulation with real-time latency visualization, network profiles, and error pattern scripting.

Key Features:

  • Real-time latency visualization
  • Network profile management (slow 3G, flaky Wi-Fi, etc.)
  • Error pattern scripting (burst, random, sequential)
  • Profile export/import
  • CLI integration

Learn More: Chaos Lab Documentation

Reality Slider

Unified control mechanism that adjusts mock environment realism from simple static stubs to full production-level chaos.

Key Features:

  • Configurable realism levels (1–5)
  • Automated toggling of chaos, latency, and MockAI behaviors
  • Persistent slider state per environment
  • Export/import of realism presets
  • Keyboard shortcuts for quick changes

Learn More: Reality Slider Documentation

Reality Profiles Marketplace

Pre-tuned “realism packs” that bundle personas, scenarios, chaos rules, latency curves, error distributions, and protocol behaviors into ready-to-use packages.

Key Features:

  • E-Commerce Peak Season Pack
  • Fintech Fraud Pack
  • Healthcare HL7/Insurance Edge Cases Pack
  • IoT Device Fleet Chaos Pack
  • Custom pack creation

Learn More: Reality Profiles Marketplace Documentation

Behavioral Economics Engine

Makes mocks react to real-world pressures like latency, load, pricing changes, fraud suspicion, and customer segments.

Key Features:

  • Cart conversion drops if latency > 400ms
  • Bank declines transactions if prior balance checks failed
  • User churn increases after multiple 500s
  • Declarative and scriptable rules

Learn More: Behavioral Economics Engine Documentation

World State Engine

Unified visualization of all MockForge state systems—like a “miniature game engine for your backend.”

Key Features:

  • Unified state aggregation from all subsystems
  • Graph visualization
  • Real-time updates
  • Time travel
  • Query interface

Learn More: World State Engine Documentation

Performance Mode

Lightweight load simulation for running scenarios at N RPS, simulating bottlenecks, and recording latencies.

Key Features:

  • Run scenarios at n RPS
  • Simulate bottlenecks
  • Record latencies
  • Observe response changes under load

Learn More: Performance Mode Documentation

Drift Learning

Mocks learn from recorded traffic patterns and adapt their behavior over time.

Key Features:

  • Traffic pattern learning from recorded requests
  • Persona behavior adaptation
  • Configurable learning modes (behavioral, statistical, hybrid)
  • Opt-in per endpoint/persona learning

Learn More: Drift Learning Documentation

Collaboration & Cloud

Cloud Workspaces

Multi-user collaborative editing with real-time state synchronization, version control, and role-based permissions.

Key Features:

  • User authentication and access control
  • Multi-user environment editing
  • State synchronization between clients
  • Git-style version control for mocks and data
  • Role-based permissions (Owner, Editor, Viewer)

Learn More: Cloud Workspaces Documentation

Data Scenario Marketplace

Marketplace for downloadable mock templates with tags, ratings, versioning, and one-click import/export.

Key Features:

  • Marketplace for downloadable mock templates
  • Tags, ratings, and versioning
  • One-click import/export
  • Domain-specific packs (e-commerce, fintech, IoT)
  • Automatic schema and route alignment

Learn More: Scenario Marketplace Documentation

MockOps Pipelines

GitHub Actions-like automation for mock lifecycle management with event-driven pipelines.

Key Features:

  • Schema change → auto-regenerate SDK
  • Scenario published → auto-promote to test → notify teams
  • Drift threshold exceeded → auto-generate Git PR
  • Event-driven automation

Learn More: MockOps Pipelines Documentation

Multi-Workspace Federation

Compose multiple mock workspaces into one federated “virtual system” for large organizations with microservices.

Key Features:

  • Service boundary definition
  • Compose workspaces into virtual systems
  • System-wide scenarios
  • Per-service reality level control

Learn More: Federation Documentation

Analytics Dashboard

Leadership insight into coverage, risk, and usage with heatmaps, CI tracking, and coverage analysis.

Key Features:

  • Scenario usage heatmaps
  • Persona CI hit tracking
  • Endpoint coverage analysis
  • Reality level staleness detection
  • Drift percentage tracking

Learn More: Analytics Dashboard Documentation

Developer Experience

ForgeConnect SDK

Browser extension and SDK for capturing network traffic, auto-generating mocks, and integrating with popular frameworks.

Key Features:

  • Browser extension to capture network traffic
  • Auto-mock generation for unhandled requests
  • Local mock preview in browser
  • SDK for framework bindings (React, Vue, Angular)
  • Auth passthrough support for OAuth flows

Learn More: ForgeConnect SDK Documentation

Zero-Config Mode (Runtime Daemon)

The “invisible mock server” experience—automatically creates mocks, generates types, and sets up scenarios when you hit non-existent endpoints.

Key Features:

  • Auto-detection of 404 responses
  • Automatic mock creation
  • Type generation
  • Client stub generation
  • OpenAPI schema updates

Learn More: Zero-Config Mode Documentation

Snapshot Diff

Side-by-side visualization for comparing mock behavior between environments, personas, scenarios, or reality levels.

Key Features:

  • Compare test vs prod
  • Compare personas
  • Compare reality levels
  • Side-by-side visualization

Learn More: Snapshot Diff Documentation

Mock-Oriented Development (MOD)

A software development methodology that places mocks at the center of the development workflow.

Key Features:

  • Mock-first design
  • Contract-driven development
  • Reality progression
  • Scenario-driven testing

Learn More: MOD Documentation

Experimental Features

Deceptive Deploys

Deploy mock APIs that look identical to production endpoints, perfect for demos, PoCs, and client presentations.

Key Features:

  • Production-like headers and response patterns
  • Production-like CORS configuration
  • Production-like rate limiting
  • OAuth flow simulation
  • Auto-tunnel deployment

Learn More: Deceptive Deploys Documentation

Voice + LLM Interface

Generate OpenAPI specifications and mock APIs from natural language voice commands.

Key Features:

  • Voice command parsing with LLM
  • OpenAPI spec generation from voice commands
  • Conversational mode for multi-turn interactions
  • Single-shot mode for complete commands
  • CLI and Web UI integration

Learn More: Voice + LLM Interface Documentation

Reality Continuum

Gradually transition from mock to real backend data by intelligently blending responses from both sources.

Key Features:

  • Dynamic blending of mock and real responses
  • Time-based progression with virtual clock integration
  • Per-route, group-level, and global blend ratios
  • Multiple merge strategies
  • Fallback handling for failures

Learn More: Reality Continuum Documentation

Smart Personas

Generate coherent, consistent mock data using persona profiles with unique backstories and deterministic generation.

Key Features:

  • Persona profile system with unique IDs and domains
  • Coherent backstories with template-based generation
  • Persona relationships (connections between personas)
  • Deterministic data generation (same persona = same data)
  • Domain-specific persona templates

Learn More: Smart Personas Documentation

Getting Started

To get started with advanced features:

  1. Review the feature documentation linked above for detailed information
  2. Check configuration examples in the Configuration Guide
  3. Try the tutorials in the Tutorials section
  4. Explore examples in the examples/ directory

Feature Comparison

FeatureUse CaseComplexity
VBR EngineStateful CRUD operationsMedium
Temporal SimulationTime-based testingMedium
MockAIIntelligent responsesHigh
Chaos LabResilience testingLow
Reality SliderQuick realism adjustmentLow
Cloud WorkspacesTeam collaborationMedium
ForgeConnect SDKBrowser-based developmentLow

Best Practices

  1. Start Simple: Begin with basic features (Chaos Lab, Reality Slider) before moving to advanced features
  2. Read Documentation: Each feature has detailed documentation with examples
  3. Use Examples: Check the examples/ directory for working configurations
  4. Test Incrementally: Enable features one at a time to understand their impact
  5. Monitor Performance: Some features (like MockAI) may add latency

Temporal Simulation (Time Travel)

Temporal Simulation allows you to control time in your mock environment, enabling time-based data mutations, scheduled events, and time-travel debugging. Test time-dependent behavior without waiting for real time to pass.

Overview

Time travel in MockForge works through a virtual clock that can be:

  • Enabled/disabled at runtime
  • Set to any specific point in time
  • Advanced by arbitrary durations instantly
  • Scaled to run faster or slower than real time

When time travel is enabled, all time-related features use the virtual clock instead of the system clock.

Quick Start

Enable Time Travel

# config.yaml
core:
  time_travel:
    enabled: true
    initial_time: "2025-01-01T00:00:00Z"
    scale_factor: 1.0
    enable_scheduling: true

Control Time via CLI

# Get time travel status
mockforge time status

# Enable time travel at a specific time
mockforge time enable --time "2025-01-01T00:00:00Z"

# Advance time by 1 month (instantly!)
mockforge time advance 1month

# Advance time by 2 hours
mockforge time advance 2h

# Set time to a specific point
mockforge time set "2025-06-01T12:00:00Z"

# Reset to real time
mockforge time reset

Use Time-Based Templates

Time-aware template tokens automatically use the virtual clock:

{
  "timestamp": "{{now}}",
  "expires_at": "{{now+1h}}",
  "created_at": "{{now-30m}}"
}

Virtual Clock

The virtual clock is the core of temporal simulation. It provides:

Basic Operations

#![allow(unused)]
fn main() {
use mockforge_core::time_travel::VirtualClock;

let clock = VirtualClock::new();

// Enable and set time
clock.enable_and_set(DateTime::parse_from_rfc3339("2025-01-01T00:00:00Z")?);

// Advance time
clock.advance(Duration::from_secs(3600)); // Advance 1 hour

// Get current virtual time
let now = clock.now();

// Disable (return to real time)
clock.disable();
}

Time Scale

Run time faster or slower than real time:

# Run at 2x speed
mockforge time scale 2.0

# Run at 0.5x speed (half speed)
mockforge time scale 0.5

Cron Scheduler

Schedule recurring events using cron expressions:

Create Cron Job

# Via CLI (action metadata is read from a JSON file)
echo '{"status": 200, "body": {"event": "cleanup"}}' > cleanup-action.json
mockforge time cron create cleanup-job \
  --name "Cleanup" \
  --schedule "0 */6 * * *" \
  --action-type "response" \
  --action-metadata cleanup-action.json

# Via API
curl -X POST http://localhost:9080/__mockforge/time-travel/cron \
  -H "Content-Type: application/json" \
  -d '{
    "id": "cleanup-job",
    "name": "Cleanup",
    "schedule": "0 */6 * * *",
    "action_type": "response",
    "action_metadata": {"status": 200, "body": {"event": "cleanup"}}
  }'

Supported action types are callback (logs the execution), response (metadata keys body, status, headers), and mutation.

Cron Expression Format

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
* * * * *

Examples:

  • 0 */6 * * * - Every 6 hours
  • 0 0 * * * - Daily at midnight
  • */15 * * * * - Every 15 minutes
  • 0 9 * * 1-5 - Weekdays at 9 AM

List Cron Jobs

# Via CLI
mockforge time cron list

# Via API
curl http://localhost:9080/__mockforge/time-travel/cron

Mutation Rules

Automatically mutate data based on time triggers:

Interval-Based Mutations

Mutate data at regular intervals:

# Create mutation rule (trigger and operation configs are JSON files)
echo '{"duration_seconds": 3600}' > trigger.json
echo '{"status": "shipped"}' > operation.json
mockforge time mutation create ship-orders \
  --entity "orders" \
  --trigger-type interval \
  --trigger-config trigger.json \
  --operation-type status \
  --operation-config operation.json

# Via API
curl -X POST http://localhost:9080/__mockforge/time-travel/mutations \
  -H "Content-Type: application/json" \
  -d '{
    "id": "ship-orders",
    "entity_name": "orders",
    "trigger": {
      "type": "interval",
      "duration_seconds": 3600
    },
    "operation": {
      "type": "updatestatus",
      "status": "shipped"
    }
  }'

Time-Based Mutations

Mutate data at specific times:

{
  "entity": "tokens",
  "trigger": {
    "type": "at_time",
    "time": "2025-01-01T12:00:00Z"
  },
  "operation": {
    "type": "set",
    "field": "expired",
    "value": true
  }
}

Field Threshold Mutations

Mutate when a field reaches a threshold:

{
  "entity": "orders",
  "trigger": {
    "type": "field_threshold",
    "field": "age_days",
    "operator": ">=",
    "value": 30
  },
  "operation": {
    "type": "set",
    "field": "status",
    "value": "archived"
  }
}

Scheduled Responses

Schedule responses to be sent at specific times:

# Schedule a response for 30 minutes from now
curl -X POST http://localhost:9080/__mockforge/time-travel/schedule \
  -H "Content-Type: application/json" \
  -d '{
    "trigger_time": "+30m",
    "path": "/api/notifications",
    "method": "POST",
    "body": {"event": "token_expired"},
    "status": 401
  }'

VBR Integration

Temporal simulation integrates with the VBR Engine for time-based data mutations:

Snapshot with Time Travel

Create snapshots that include time travel state:

#![allow(unused)]
fn main() {
use mockforge_vbr::VbrEngine;

// Create snapshot with time travel state
engine.create_snapshot_with_time_travel(
    "snapshot1",
    Some("Description".to_string()),
    "./snapshots",
    &clock
).await?;

// Restore snapshot with time travel state
engine.restore_snapshot_with_time_travel(
    "snapshot1",
    "./snapshots",
    &clock
).await?;
}

Mutation Rules in VBR

VBR automatically executes mutation rules based on virtual time:

vbr:
  entities:
    - name: orders
      mutation_rules:
        - trigger: "interval:1h"
          operation: "update_status"
          field: "status"
          value: "processing"

Admin API

Time Travel Status

GET /__mockforge/time-travel/status

Response:

{
  "enabled": true,
  "virtual_time": "2025-01-15T10:30:00Z",
  "real_time": "2025-01-01T10:30:00Z",
  "scale_factor": 1.0
}

Advance Time

POST /__mockforge/time-travel/advance
Content-Type: application/json

{
  "duration": "2h"  # or "1month", "30m", etc.
}

Set Time

POST /__mockforge/time-travel/set
Content-Type: application/json

{
  "time": "2025-06-01T12:00:00Z"
}

Enable/Disable

POST /__mockforge/time-travel/enable
Content-Type: application/json

{
  "time": "2025-01-01T00:00:00Z"  # Optional initial time
}
POST /__mockforge/time-travel/disable

CLI Commands

Time Control

# Status
mockforge time status

# Enable
mockforge time enable [--time "2025-01-01T00:00:00Z"]

# Disable
mockforge time disable

# Advance
mockforge time advance <duration>  # e.g., "1month", "2h", "30m"

# Set
mockforge time set <time>  # ISO 8601 format

# Scale
mockforge time scale <factor>  # e.g., 2.0 for 2x speed

# Reset
mockforge time reset

Cron Jobs

# List
mockforge time cron list

# Create
mockforge time cron create <id> --name "<name>" --schedule "<cron>" --action-type <callback|response|mutation> [--action-metadata <file.json>]

# Get
mockforge time cron get <id>

# Enable / disable
mockforge time cron enable <id>
mockforge time cron disable <id>

# Delete
mockforge time cron delete <id>

Mutation Rules

# List
mockforge time mutation list

# Create
mockforge time mutation create <id> --entity "<entity>" \
  --trigger-type <interval|attime> --trigger-config <trigger.json> \
  --operation-type <set|increment|decrement|status> --operation-config <operation.json>

# Get
mockforge time mutation get <id>

# Enable / disable
mockforge time mutation enable <id>
mockforge time mutation disable <id>

# Delete
mockforge time mutation delete <id>

Use Cases

Token Expiration

Test token expiration without waiting:

# Create token that expires in 1 hour
mockforge time enable --time "2025-01-01T00:00:00Z"

# Advance 1 hour
mockforge time advance 1h

# Token is now expired

Session Timeouts

Test session timeout behavior:

vbr:
  entities:
    - name: sessions
      ttl_seconds: 3600  # 1 hour
      aging_enabled: true

Scheduled Events

Test scheduled notifications:

# Schedule a daily report response at midnight
echo '{"status": 200, "body": {"event": "daily_report"}}' > daily-report.json
mockforge time cron create daily-report \
  --name "Daily report" \
  --schedule "0 0 * * *" \
  --action-type "response" \
  --action-metadata daily-report.json

Data Aging

Test data that changes over time:

# Create mutation rule to age orders once per day
echo '{"duration_seconds": 86400}' > daily.json
echo '{"field": "age_days", "amount": 1}' > increment.json
mockforge time mutation create age-orders \
  --entity "orders" \
  --trigger-type interval \
  --trigger-config daily.json \
  --operation-type increment \
  --operation-config increment.json

Best Practices

  1. Start with Simple Scenarios: Begin with basic time advancement before using cron or mutations
  2. Use Snapshots: Save important time states for quick restoration
  3. Test Edge Cases: Test behavior at midnight, month boundaries, etc.
  4. Monitor Performance: Time-based features add minimal overhead
  5. Combine with VBR: Use VBR entities with time-based mutations for realistic scenarios

Troubleshooting

Time Not Advancing

  • Ensure time travel is enabled: mockforge time status
  • Check that scheduling is enabled in configuration
  • Verify cron jobs are enabled

Mutations Not Executing

  • Check mutation rule is enabled
  • Verify trigger conditions are met
  • Review server logs for errors

Cron Jobs Not Running

  • Ensure cron scheduler background task is running
  • Check cron expression is valid
  • Verify job is enabled

Scenario State Machines 2.0

Scenario State Machines 2.0 provides a visual flow editor for modeling complex workflows and multi-step scenarios. Create state machines with conditional transitions, reusable sub-scenarios, and real-time state tracking.

Overview

State machines enable you to model complex API behaviors that depend on previous interactions:

  • Visual Flow Editor: Drag-and-drop interface for creating state machines
  • Conditional Transitions: If/else logic for state transitions
  • Reusable Sub-Scenarios: Compose complex workflows from simpler components
  • Real-Time Preview: See active state and available transitions
  • VBR Integration: Synchronize state with VBR entities

Quick Start

Create a State Machine

  1. Navigate to State Machines in the Admin UI
  2. Click Create New State Machine
  3. Add states and transitions using the visual editor
  4. Configure conditions for transitions
  5. Save the state machine

Basic Example: Order Workflow

name: order_workflow
initial_state: pending
states:
  - name: pending
    response:
      status_code: 200
      body: '{"order_id": "{{resource_id}}", "status": "pending"}'
  
  - name: processing
    response:
      status_code: 200
      body: '{"order_id": "{{resource_id}}", "status": "processing"}'
  
  - name: shipped
    response:
      status_code: 200
      body: '{"order_id": "{{resource_id}}", "status": "shipped"}'

transitions:
  - from: pending
    to: processing
    condition: 'method == "PUT" && path == "/api/orders/{id}/process"'
  
  - from: processing
    to: shipped
    condition: 'method == "PUT" && path == "/api/orders/{id}/ship"'

Visual Editor

The visual editor provides a React Flow-based interface for creating state machines:

Adding States

  1. Click Add State button
  2. Configure state name and response
  3. Position state on canvas
  4. Connect states with transitions

Creating Transitions

  1. Drag from one state to another
  2. Configure transition condition
  3. Set transition metadata (optional)

Editing States

  • Double-click a state to edit
  • Right-click for context menu
  • Drag to reposition

Conditional Transitions

Transitions can include conditions that determine when they execute:

Method-Based Conditions

transitions:
  - from: pending
    to: processing
    condition: 'method == "POST" && path == "/api/orders/{id}/process"'

Header-Based Conditions

transitions:
  - from: pending
    to: processing
    condition: 'header["X-Admin"] == "true"'

Body-Based Conditions

transitions:
  - from: pending
    to: processing
    condition: 'body.status == "ready"'

Complex Conditions

transitions:
  - from: pending
    to: processing
    condition: '(method == "PUT" || method == "PATCH") && body.amount > 100'

Sub-Scenarios

Create reusable sub-scenarios that can be embedded in larger workflows:

Define Sub-Scenario

name: payment_processing
states:
  - name: initiated
  - name: processing
  - name: completed
  - name: failed

transitions:
  - from: initiated
    to: processing
    condition: 'method == "POST" && path == "/api/payments"'

Use Sub-Scenario

name: order_workflow
states:
  - name: pending
  - name: payment
    sub_scenario: payment_processing
  - name: completed

transitions:
  - from: pending
    to: payment
    condition: 'method == "POST" && path == "/api/orders/{id}/pay"'
  
  - from: payment
    to: completed
    condition: 'sub_scenario_state == "completed"'

VBR Integration

Synchronize state machine state with VBR entities:

Configure VBR Entity

vbr:
  entities:
    - name: orders
      state_machine: order_workflow
      state_field: status

State Synchronization

When a state transition occurs, the corresponding VBR entity is updated:

# Transition order to processing
PUT /api/orders/123/process

# VBR entity automatically updated
GET /vbr-api/orders/123
# Response: {"id": 123, "status": "processing", ...}

API Endpoints

The state machine API is part of the management API on the HTTP mock server (default port 3000), under /__mockforge/api/state-machines. State machines are keyed by their resource_type; instances are keyed by resource_id.

State Machine CRUD

# Create (or replace) a state machine
POST /__mockforge/api/state-machines
Content-Type: application/json

{
  "state_machine": {
    "resource_type": "order",
    "initial_state": "pending",
    "states": ["pending", "processing", "shipped"],
    "transitions": [...]
  },
  "visual_layout": null
}

# List state machines
GET /__mockforge/api/state-machines

# Get one state machine
GET /__mockforge/api/state-machines/{resource_type}

# Update a state machine (same body as create)
PUT /__mockforge/api/state-machines/{resource_type}

# Delete a state machine
DELETE /__mockforge/api/state-machines/{resource_type}

State Instances

# Create a state instance
POST /__mockforge/api/state-machines/instances
Content-Type: application/json

{
  "resource_id": "order-123",
  "resource_type": "order"
}

# List instances
GET /__mockforge/api/state-machines/instances

# Get an instance
GET /__mockforge/api/state-machines/instances/{resource_id}

# Transition an instance
POST /__mockforge/api/state-machines/instances/{resource_id}/transition
Content-Type: application/json

{
  "resource_id": "order-123",
  "to_state": "processing",
  "context": null
}

Current State

# Get current state
GET /__mockforge/api/state-machines/instances/{resource_id}/state

# Get next possible states
GET /__mockforge/api/state-machines/instances/{resource_id}/next-states

Import/Export

Export and import work on all state machines at once:

# Export all state machines (and their visual layouts)
GET /__mockforge/api/state-machines/export

# Import state machines (same shape as the export response)
POST /__mockforge/api/state-machines/import
Content-Type: application/json

{
  "state_machines": [...],
  "visual_layouts": {}
}

Real-Time Updates

State machines support real-time updates via WebSocket:

WebSocket Events

{
  "type": "state_machine_transition",
  "state_machine_id": "uuid",
  "instance_id": "uuid",
  "from_state": "pending",
  "to_state": "processing",
  "timestamp": "2025-01-15T10:30:00Z"
}

Subscribe to Updates

const ws = new WebSocket('ws://localhost:9080/ws');
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'state_machine_transition') {
    console.log('State transition:', data);
  }
};

Undo/Redo

The visual editor supports undo/redo operations:

  • Undo: Ctrl+Z or Cmd+Z
  • Redo: Ctrl+Shift+Z or Cmd+Shift+Z
  • History: View edit history in editor

Use Cases

Order Processing Workflow

Model a complete order lifecycle:

states:
  - pending
  - payment_pending
  - payment_processing
  - payment_completed
  - payment_failed
  - processing
  - shipped
  - delivered
  - cancelled

User Onboarding

Track user onboarding progress:

states:
  - signup
  - email_verification
  - profile_setup
  - onboarding_complete

Approval Workflows

Model multi-step approval processes:

states:
  - draft
  - submitted
  - review
  - approved
  - rejected

Best Practices

  1. Start Simple: Begin with basic state machines before adding complexity
  2. Use Sub-Scenarios: Break complex workflows into reusable components
  3. Test Transitions: Verify all transitions work as expected
  4. Document Conditions: Keep transition conditions well-documented
  5. Version Control: Export and version control state machine definitions

Troubleshooting

State Not Transitioning

  • Verify transition condition is correct
  • Check that request matches condition
  • Review server logs for errors

Sub-Scenario Not Executing

  • Ensure sub-scenario is properly defined
  • Verify input/output mapping is correct
  • Check sub-scenario state transitions

VBR Sync Issues

  • Verify VBR entity configuration
  • Check state field name matches
  • Review VBR entity state

MockAI (Intelligent Mocking)

MockAI is MockForge’s intelligent mock generation system that uses AI to create contextually appropriate, realistic API responses. It automatically learns from OpenAPI specifications and example payloads to generate intelligent behavior.

Overview

MockAI provides:

  • Auto-Generated Rules: Automatically infers behavioral rules from OpenAPI specs or example payloads
  • Context-Aware Responses: Maintains session state and conversation history across requests
  • Mutation Detection: Intelligently detects create, update, and delete operations from request changes
  • Validation Error Generation: Generates realistic, context-aware validation error responses
  • Pagination Intelligence: Automatically generates realistic pagination metadata and responses
  • Session Persistence: Tracks state across multiple requests within a session

Quick Start

Enable MockAI

# config.yaml
mockai:
  enabled: true
  auto_learn: true
  mutation_detection: true
  ai_validation_errors: true
  intelligent_pagination: true

Start Server

mockforge serve --config config.yaml --spec api.yaml

MockAI will automatically:

  • Learn from your OpenAPI specification
  • Generate intelligent responses
  • Track session state
  • Handle mutations and pagination

Configuration

Basic Configuration

mockai:
  enabled: true
  auto_learn: true
  mutation_detection: true
  ai_validation_errors: true
  intelligent_pagination: true
  intelligent_behavior:
    behavior_model:
      provider: "ollama"  # or "openai", "anthropic"
      model: "llama3.2"
      base_url: "http://localhost:11434"

LLM Provider Configuration

Ollama (Local, Free)

mockai:
  intelligent_behavior:
    behavior_model:
      provider: "ollama"
      model: "llama3.2"
      base_url: "http://localhost:11434"

OpenAI

mockai:
  intelligent_behavior:
    behavior_model:
      provider: "openai"
      model: "gpt-3.5-turbo"
      api_key: "${OPENAI_API_KEY}"
      temperature: 0.7
      max_tokens: 1000

Anthropic

mockai:
  intelligent_behavior:
    behavior_model:
      provider: "anthropic"
      model: "claude-3-sonnet-20240229"
      api_key: "${ANTHROPIC_API_KEY}"

Performance Tuning

mockai:
  intelligent_behavior:
    performance:
      max_history_length: 100
      cache_enabled: true
      cache_ttl_seconds: 3600
      timeout_seconds: 30

CLI Commands

Enable/Disable MockAI

# Enable globally
mockforge mockai enable

# Enable for specific endpoints
mockforge mockai enable --endpoint "/users" --endpoint "/products"

# Disable globally
mockforge mockai disable

# Disable for specific endpoints
mockforge mockai disable --endpoint "/admin/*"

Check Status

mockforge mockai status

Learn from Examples

# Learn from example request/response pairs
mockforge mockai learn --from-examples examples.json

Generate Rules from OpenAPI

# Generate behavioral rules from an OpenAPI spec
mockforge mockai generate --from-openapi api.yaml --output rules.yaml

Session Management

MockAI automatically tracks sessions to maintain context across requests:

Session Identification

Sessions are identified by:

  • Header: X-Session-ID: <session-id>
  • Cookie: mockforge_session=<session-id>

If no session ID is provided, MockAI generates a new one automatically.

Example with Session

# First request - creates session
curl http://localhost:3000/users

# Response includes session ID in Set-Cookie header
# Subsequent requests use the same session

# Second request with session
curl -H "X-Session-ID: my-session-123" \
     http://localhost:3000/users

Mutation Detection

MockAI automatically detects mutations (create, update, delete) by comparing request bodies:

Create Detection

# First request - creates a new resource
curl -X POST http://localhost:3000/users \
     -H "Content-Type: application/json" \
     -d '{"name": "John", "email": "[email protected]"}'

# MockAI detects this as a create operation
# Response includes generated ID and created timestamp

Update Detection

# Second request with changes - detected as update
curl -X POST http://localhost:3000/users \
     -H "Content-Type: application/json" \
     -H "X-Session-ID: my-session-123" \
     -d '{"name": "John Doe", "email": "[email protected]"}'

# MockAI detects changes and treats as update
# Response reflects updated values

Validation Errors

MockAI generates realistic validation errors when requests don’t match schemas:

Missing Required Field

curl -X POST http://localhost:3000/users \
     -H "Content-Type: application/json" \
     -d '{"email": "invalid"}'  # Missing "name" field

Response:

{
  "error": "Validation failed",
  "details": [
    {
      "field": "name",
      "message": "Field 'name' is required"
    },
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ]
}

Pagination

MockAI automatically handles pagination requests:

Paginated Request

curl "http://localhost:3000/users?page=1&limit=10"

Response:

{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 100,
    "total_pages": 10,
    "has_next": true,
    "has_prev": false
  }
}

Programmatic Usage

Create MockAI from OpenAPI

#![allow(unused)]
fn main() {
use mockforge_core::intelligent_behavior::{IntelligentBehaviorConfig, MockAI};
use mockforge_core::openapi::OpenApiSpec;

// Load OpenAPI spec
let spec = OpenApiSpec::from_file("api.yaml").await?;

// Create MockAI with default config
let config = IntelligentBehaviorConfig::default();
let mockai = MockAI::from_openapi(&spec, config).await?;

// Process a request
let request = Request {
    method: "POST".to_string(),
    path: "/users".to_string(),
    body: Some(json!({"name": "John"})),
    query_params: HashMap::new(),
    headers: HashMap::new(),
};

let response = mockai.process_request(&request).await?;
}

Learn from Examples

#![allow(unused)]
fn main() {
use mockforge_core::intelligent_behavior::rule_generator::ExamplePair;

let examples = vec![
    ExamplePair {
        method: "POST".to_string(),
        path: "/users".to_string(),
        request: Some(json!({"name": "John"})),
        response: Some(json!({"id": 1, "name": "John"})),
    },
];

mockai.learn_from_example(examples[0]).await?;
}

Use Cases

Rapid Prototyping

Generate realistic API responses without writing fixtures:

mockai:
  enabled: true
  auto_learn: true

Testing Error Handling

Generate realistic validation errors:

mockai:
  enabled: true
  ai_validation_errors: true

Session-Based Testing

Test multi-step workflows with session persistence:

# Step 1: Create session
curl -X POST http://localhost:3000/sessions

# Step 2: Use session in subsequent requests
curl -H "X-Session-ID: <session-id>" \
     http://localhost:3000/users

Best Practices

  1. Start with Defaults: Begin with default configuration and adjust as needed
  2. Use Local LLMs: For faster responses, use Ollama or similar local providers
  3. Monitor Performance: Track response times and adjust timeout_seconds accordingly
  4. Session Management: Use consistent session IDs across related requests
  5. Example Quality: Provide high-quality examples for better rule generation

Troubleshooting

MockAI Not Responding

  1. Check if MockAI is enabled:

    mockforge mockai status
    
  2. Verify LLM provider is accessible:

    # For Ollama
    curl http://localhost:11434/api/tags
    
  3. Check logs for errors:

    mockforge serve --log-level debug
    

Session Not Persisting

  • Ensure session ID is sent in headers or cookies
  • Check session timeout settings
  • Verify session storage is not being cleared

Slow Responses

  • Use a smaller/faster model
  • Enable caching
  • Reduce max_history_length
  • Use a local LLM provider (Ollama)

Limitations

  • Query parameter extraction currently requires middleware enhancement
  • Session contexts are stored in memory (not persisted to disk)
  • Large OpenAPI specs may take longer to initialize

AI / RAG-Driven Mock Data

MockForge ships two distinct AI-related capabilities; this chapter covers both because they’re easy to confuse:

FeatureWhat it doesWhere it runs
MockAI (response generation)Produces realistic responses from natural-language prompts at request timeIn the request path
RAG-driven data synthesis (mockforge data ...)Generates static fixture files at build time using LLM + retrievalOne-shot CLI

Use MockAI when you want responses to vary intelligently per request. Use RAG synthesis when you want a deterministic fixture file you can check into git.

For MockAI request-time response generation, see the existing MockAI chapter. This chapter focuses on the mockforge data CLI — the build-time fixture generator.

What mockforge data is for

You have an OpenAPI spec or a JSON schema. You want sample data to test against. Three options, in increasing intelligence:

  1. Static fixtures you write by hand. Tedious; doesn’t scale; gets stale.
  2. faker-based generation — {{faker.name}}, {{faker.email}} etc. Realistic individual fields, but the rows don’t relate to each other (a User named “Alice Smith” with email [email protected]).
  3. RAG-driven generation — an LLM looks at field names + schema + relationships and produces semantically coherent rows. A User named “Alice Smith” gets [email protected] and a plausible bio.

Option 3 is what mockforge data provides.

Quick start

Generate 100 realistic users using OpenAI:

export MOCKFORGE_RAG_API_KEY=sk-...
mockforge data template user --rows 100 --rag --rag-provider openai \
  --output users.json

Generate from your own schema:

mockforge data schema my-schema.json --rows 50 \
  --format jsonl --output data.jsonl

Generate from an OpenAPI spec (per-schema):

mockforge data mock-openapi api.yaml --rows 25 --realistic \
  --output mock-data.json

Spin up a mock server backed by AI-generated data:

mockforge data mock-server api.yaml --port 3000 --realistic

Subcommand reference

data template <NAME>

Built-in templates: user, product, order. Each has an internal schema with realistic field relationships baked in.

mockforge data template user --rows 10 --format json
mockforge data template product --rows 50 --output products.csv --format csv
mockforge data template order --rows 20 --rag --rag-provider openai \
  --output orders.json

Common flags:

  • -r, --rows <N> — row count (default 10)
  • -f, --format <FMT> — json | csv | jsonl
  • -o, --output <PATH> — output file (stdout if omitted)
  • --rag — enable RAG enhancement (otherwise pure faker)
  • --rag-provider <P> — openai | anthropic | ollama | openai_compatible
  • --rag-model <M> — model name (provider default if omitted)
  • --rag-endpoint <URL> — custom endpoint (e.g. self-hosted Ollama)
  • --rag-timeout <SECS>, --rag-max-retries <N> — request tuning

data schema <SCHEMA>

Generate from a JSON Schema document.

mockforge data schema schemas/order.json --rows 100 \
  --format jsonl --output orders.jsonl

Same --rag* flags apply.

data mock-openapi <SPEC>

Walk every schema in an OpenAPI spec and generate sample data per schema.

mockforge data mock-openapi api-spec.yaml --rows 50 --realistic \
  --output mock-data.json

mockforge data mock-openapi api-spec.json --validate --include-optional \
  --output mock-data.json

Flags:

  • --realistic — use RAG (defaults to faker-only)
  • --validate — verify generated rows against the schema before writing
  • --include-optional — generate optional fields too (otherwise required-only)

data mock-server <SPEC>

End-to-end shortcut: spin up a HTTP server backed by AI-generated data without writing config files.

mockforge data mock-server api.yaml --port 3000 --realistic

This is what you reach for when you want to demo a third-party API to your team in 30 seconds. For long-term mocks, write a config file and use mockforge serve.

Provider setup

OpenAI

export MOCKFORGE_RAG_PROVIDER=openai
export MOCKFORGE_RAG_API_KEY=sk-...
export MOCKFORGE_RAG_MODEL=gpt-4o-mini   # cheaper than gpt-4
mockforge data template user --rows 100 --rag

Cost tip: gpt-4o-mini and gpt-3.5-turbo are sufficient for fixture generation. The model only sees a schema + field names, not your production data; you don’t need a frontier model.

Anthropic

export MOCKFORGE_RAG_PROVIDER=anthropic
export MOCKFORGE_RAG_API_KEY=sk-ant-...
export MOCKFORGE_RAG_MODEL=claude-3-5-haiku-20241022
mockforge data template user --rows 100 --rag

Ollama (local, free)

For development and CI where you don’t want to spend on API calls:

# In one terminal
ollama serve
ollama pull llama3

# In another
export MOCKFORGE_RAG_PROVIDER=ollama
export MOCKFORGE_RAG_MODEL=llama3
export MOCKFORGE_RAG_API_ENDPOINT=http://localhost:11434/api/generate
mockforge data template user --rows 100 --rag

This is the recommended path for CI generation — no network calls out, no spend per build.

OpenAI-compatible (LM Studio, vLLM, Ollama OpenAI mode, etc.)

export MOCKFORGE_RAG_PROVIDER=openai_compatible
export MOCKFORGE_RAG_API_ENDPOINT=http://localhost:8000/v1/chat/completions
export MOCKFORGE_RAG_MODEL=local-model-name
mockforge data template user --rows 100 --rag

For schemas with cross-references (e.g. Order.user_id → User.id), RAG optionally uses embeddings to keep references coherent. Configure with:

export MOCKFORGE_EMBEDDING_PROVIDER=openai      # or local | ollama
export MOCKFORGE_EMBEDDING_MODEL=text-embedding-3-small
export MOCKFORGE_EMBEDDING_ENDPOINT=http://localhost:11434  # for local
export MOCKFORGE_SIMILARITY_THRESHOLD=0.75      # 0.0-1.0
export MOCKFORGE_SEMANTIC_SEARCH=true

Without embeddings, foreign-key fields get random valid IDs. With embeddings, MockForge picks IDs whose adjacent fields are semantically related to the row being generated.

Cost / latency tradeoffs

SetupCost per 1K rowsLatency
Faker only (no --rag)$0< 1 s
Ollama local$030-120 s (CPU) / 5-15 s (GPU)
OpenAI gpt-4o-mini~$0.0110-30 s
OpenAI gpt-4~$0.3030-90 s
Anthropic claude-3-5-haiku~$0.0515-30 s

Caching: results are cached by (schema, prompt, model) tuple, so repeated runs of the same mockforge data template ... are free after the first.

CI patterns

Pattern 1: Generate fixtures, check them in.

# .github/workflows/refresh-fixtures.yml
on:
  schedule:
    - cron: '0 0 * * 0'   # weekly
jobs:
  refresh:
    steps:
      - uses: actions/checkout@v5
      - run: |
          mockforge data mock-openapi api.yaml \
            --rows 50 --realistic --validate \
            --output fixtures/mock-data.json
      - uses: peter-evans/create-pull-request@v6
        with:
          title: "chore: refresh AI-generated fixtures"

Pattern 2: Generate at test-suite startup.

# In CI before tests
mockforge data mock-server api.yaml --port 3000 --realistic &
export MOCK_URL=http://localhost:3000
npm test

Use Ollama for both patterns to keep CI free.

When NOT to use RAG generation

  • High-volume hot paths — generating 1M rows live per request is expensive. Pre-generate to a file and serve from disk.
  • Sensitive schemas — the LLM sees field names. If your schema is itself a secret (rare), use mockforge data schema with --rag off, or use Ollama locally so nothing leaves your network.
  • Tight determinism — LLMs are stochastic by default. For byte-reproducible outputs, set --rag-temperature 0 and seed faker; for full reproducibility, generate once and check the file in.

Where to go next

AI Contract Diff

AI Contract Diff automatically detects and analyzes differences between API contracts (OpenAPI specifications) and live requests. It provides contextual recommendations for mismatches and generates correction proposals to keep your contracts in sync with reality.

Overview

AI Contract Diff helps you:

  • Detect Contract Drift: Find discrepancies between your OpenAPI spec and actual API usage
  • Get AI-Powered Recommendations: Understand why mismatches occur and how to fix them
  • Generate Correction Patches: Automatically create JSON Patch files to update your specs
  • Integrate with CI/CD: Automatically verify contracts in your pipeline
  • Visualize Mismatches: Dashboard visualization of contract differences

Quick Start

Analyze a Request

# Export a capture from the running server (captures live only in its memory)
curl -s http://localhost:3000/__mockforge/api/contract-diff/captures/<capture-id> | jq .request > request.json

# Analyze the request against an OpenAPI spec
mockforge contract-diff analyze \
  --spec api.yaml \
  --request-path request.json

The CLI reads requests from a file. Captures are held only in the running server’s memory, so there is no --capture-id option; export a capture as shown above, or analyze a capture in place on the server with POST /__mockforge/api/contract-diff/analyze/{id}.

Compare Two Specs

# Compare two OpenAPI specifications
mockforge contract-diff compare \
  --old-spec api-v1.yaml \
  --new-spec api-v2.yaml

Generate Correction Patch

# Generate JSON Patch file for corrections
mockforge contract-diff generate-patch \
  --spec api.yaml \
  --request-path request.json \
  --output patch.json

How It Works

1. Request Capture

MockForge automatically captures requests for contract analysis:

# config.yaml
core:
  contract_diff:
    enabled: true
    auto_capture: true
    capture_all: false  # Only capture mismatches

2. Contract Analysis

When a request is captured, it’s analyzed against your OpenAPI specification:

  • Path Matching: Verify request path matches spec
  • Method Validation: Check HTTP method is defined
  • Header Validation: Compare request headers with spec
  • Query Parameter Validation: Verify query params match
  • Body Validation: Validate request body against schema

3. Mismatch Detection

The analyzer identifies several types of mismatches:

  • Missing Endpoint: Request path not in spec
  • Invalid Method: HTTP method not allowed
  • Missing Header: Required header not present
  • Invalid Parameter: Query param doesn’t match spec
  • Schema Mismatch: Request body doesn’t match schema
  • Type Mismatch: Value type doesn’t match spec

4. AI Recommendations

AI-powered recommendations explain mismatches:

{
  "mismatch": {
    "type": "missing_field",
    "field": "email",
    "location": "request.body"
  },
  "recommendation": {
    "message": "The 'email' field is required but missing from the request. Add it to the request body or mark it as optional in the schema.",
    "confidence": 0.95,
    "suggested_fix": "Add 'email' field to request body or update schema to make it optional"
  }
}

5. Correction Proposals

Generate JSON Patch files to fix mismatches:

[
  {
    "op": "add",
    "path": "/paths/~1users/post/requestBody/content/application~1json/schema/required",
    "value": ["email"]
  }
]

Configuration

Basic Configuration

core:
  contract_diff:
    enabled: true
    auto_capture: true
    capture_all: false
    spec_path: "./api.yaml"

AI Provider Configuration

core:
  contract_diff:
    ai_provider: "ollama"  # or "openai", "anthropic"
    ai_model: "llama3.2"
    ai_base_url: "http://localhost:11434"
    ai_api_key: "${AI_API_KEY}"  # For OpenAI/Anthropic

Webhook Configuration

core:
  contract_diff:
    webhooks:
      - url: "https://example.com/webhook"
        events: ["mismatch", "high_severity"]
        secret: "${WEBHOOK_SECRET}"

CLI Commands

Analyze Request

# Analyze a request from a file (see Quick Start for exporting a capture)
mockforge contract-diff analyze \
  --spec api.yaml \
  --request-path request.json

# With AI recommendations
mockforge contract-diff analyze \
  --spec api.yaml \
  --request-path request.json \
  --llm-provider ollama \
  --llm-model llama3.2

Compare Specs

# Compare two OpenAPI specs
mockforge contract-diff compare \
  --old-spec api-v1.yaml \
  --new-spec api-v2.yaml

# Output to file
mockforge contract-diff compare \
  --old-spec api-v1.yaml \
  --new-spec api-v2.yaml \
  --output diff.json

Generate Patch

# Generate correction patch
mockforge contract-diff generate-patch \
  --spec api.yaml \
  --request-path request.json \
  --output patch.json

generate-patch always writes the patch to the --output file; use apply-patch (below) to apply it.

Apply Patch

# Apply patch to spec
mockforge contract-diff apply-patch \
  --spec api.yaml \
  --patch patch.json \
  --output api-updated.yaml

API Endpoints

Upload Request

POST /__mockforge/contract-diff/upload
Content-Type: application/json

{
  "method": "POST",
  "path": "/users",
  "headers": {"Content-Type": "application/json"},
  "query_params": {},
  "body": {"name": "Alice", "email": "[email protected]"}
}

Get Captured Requests

GET /__mockforge/contract-diff/captures?limit=10&offset=0

Analyze Request

POST /__mockforge/contract-diff/captures/{id}/analyze
Content-Type: application/json

{
  "spec_path": "./api.yaml"
}

Generate Patch

POST /__mockforge/contract-diff/captures/{id}/patch
Content-Type: application/json

{
  "spec_path": "./api.yaml"
}

Get Statistics

GET /__mockforge/contract-diff/statistics

Dashboard

The Contract Diff dashboard provides:

  • Statistics Overview: Total captures, analyzed requests, mismatch counts
  • Captured Requests List: Browse and filter captured requests
  • Analysis Results: View mismatches, recommendations, and confidence scores
  • Patch Generation: Generate and download correction patches

Access via: Admin UI → Contract Diff

CI/CD Integration

GitHub Actions

name: Contract Diff Analysis

on:
  pull_request:
    paths:
      - 'api.yaml'
      - '**/*.yaml'

jobs:
  contract-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Analyze contracts
        run: |
          mockforge contract-diff analyze \
            --spec api.yaml \
            --request-path tests/contract/request.json
      
      - name: Generate patch
        run: |
          mockforge contract-diff generate-patch \
            --spec api.yaml \
            --request-path tests/contract/request.json \
            --output patch.json
      
      - name: Upload patch
        uses: actions/upload-artifact@v3
        with:
          name: contract-patch
          path: patch.json

GitLab CI

contract-diff:
  script:
    - mockforge contract-diff analyze --spec api.yaml --request-path tests/contract/request.json
    - mockforge contract-diff generate-patch --spec api.yaml --request-path tests/contract/request.json --output patch.json
  artifacts:
    paths:
      - patch.json

Use Cases

Contract Validation

Ensure your API spec matches actual usage:

# Analyze the most recent captured requests against the spec the server was started with
curl -X POST "http://localhost:3000/__mockforge/api/contract-diff/analyze?limit=50"

Spec Maintenance

Keep specs up-to-date automatically:

# Generate a patch for a request's mismatches
mockforge contract-diff generate-patch \
  --spec api.yaml \
  --request-path request.json \
  --output patches/patch-1.json

# Review and apply patches
mockforge contract-diff apply-patch \
  --spec api.yaml \
  --patch patches/patch-1.json \
  --output api-updated.yaml

API Versioning

Compare API versions:

# Compare v1 and v2
mockforge contract-diff compare \
  --old-spec api-v1.yaml \
  --new-spec api-v2.yaml \
  --output version-diff.json

Best Practices

  1. Enable Auto-Capture: Automatically capture requests for analysis
  2. Regular Analysis: Run analysis regularly to catch drift early
  3. Review Recommendations: Always review AI recommendations before applying
  4. Version Control Patches: Commit patches to version control
  5. CI/CD Integration: Automate contract validation in your pipeline

Troubleshooting

No Mismatches Detected

  • Verify OpenAPI spec is valid
  • Check that request path matches spec
  • Ensure method is defined in spec

AI Recommendations Not Available

  • Check AI provider is configured
  • Verify API key is set (for OpenAI/Anthropic)
  • Ensure Ollama is running (for local provider)

Patch Generation Fails

  • Verify spec path is correct
  • Check that mismatches exist
  • Review patch generation logs

Chaos Lab

Chaos Lab is an interactive module that enables you to simulate various real-world network conditions and errors directly from the UI. Test application resilience, debug network-related issues, and validate error handling logic.

Looking for the YAML / programmatic chaos engineering surface? This page covers the in-app Chaos Lab UI and predefined network profiles. For the full YAML config (latency, fault injection, per-request matchers, TCP-level connection errors, partial responses, native chunked traffic generation), see the Chaos Engineering reference and bench command examples.

Overview

Chaos Lab provides:

  • Real-time latency visualization - Visual graph showing request latency over time
  • Network profile management - Predefined and custom profiles for common network conditions
  • Error pattern scripting - Configure burst, random, or sequential error injection
  • Profile export/import - Share and version control chaos configurations
  • CLI integration - Apply profiles and manage configurations from the command line

Quick Start

Using the UI

  1. Navigate to the Chaos Engineering page in the MockForge Admin UI
  2. Use the Network Profiles section to apply predefined conditions (slow 3G, flaky Wi-Fi, etc.)
  3. Monitor real-time latency in the Latency Metrics graph
  4. Configure error patterns in the Error Pattern Editor

Using the CLI

# Apply a network profile
mockforge serve --chaos-profile slow_3g

# List available profiles
mockforge chaos profile list

# Export a profile
mockforge chaos profile export slow_3g --format json --output profile.json

# Import a profile
mockforge chaos profile import --file profile.json

Features

Real-Time Latency Graph

The latency graph displays request latency over time with:

  • Time-series visualization - See latency trends in real-time
  • Statistics overlay - Min, max, average, P95, P99 percentiles
  • Auto-refresh - Updates every 500ms for live monitoring
  • Configurable history - View last 100 samples by default

Usage:

  • Enable latency injection in the Quick Controls section
  • The graph automatically populates as requests are made
  • Hover over data points to see exact latency values

Network Profiles

Network profiles are pre-configured chaos settings that simulate specific network conditions:

Built-in Profiles

  • slow_3g - Simulates slow 3G connection (high latency, low bandwidth)
  • flaky_wifi - Intermittent connection issues with packet loss
  • high_latency - Consistent high latency for all requests
  • unstable_connection - Random connection drops and timeouts

Custom Profiles

Create your own profiles:

  1. Configure chaos settings in the Quick Controls
  2. Use the Profile Exporter to save your configuration
  3. Import it later or share with your team

Applying Profiles:

# Via UI
Click "Apply Profile" on any profile card

# Via CLI
mockforge chaos profile apply slow_3g

Error Pattern Editor

Configure sophisticated error injection patterns:

Burst Pattern

Inject multiple errors within a time window:

{
  "type": "burst",
  "count": 5,
  "interval_ms": 1000
}

This injects 5 errors within 1 second, then waits for the next interval.

Random Pattern

Inject errors with a probability:

{
  "type": "random",
  "probability": 0.1
}

Each request has a 10% chance of receiving an error.

Sequential Pattern

Inject errors in a specific order:

{
  "type": "sequential",
  "sequence": [500, 502, 503, 504]
}

Errors are injected in the specified order, then the sequence repeats.

Usage:

  1. Enable Fault Injection in Quick Controls
  2. Open the Error Pattern Editor
  3. Select pattern type and configure parameters
  4. Click “Save Pattern”

Profile Export/Import

Export and import chaos configurations for:

  • Version control - Track chaos configurations in git
  • Team sharing - Share tested configurations
  • CI/CD integration - Apply profiles in automated tests
  • Backup - Save working configurations

Export Format:

{
  "name": "custom_profile",
  "description": "Custom network condition",
  "chaos_config": {
    "latency": {
      "enabled": true,
      "fixed_delay_ms": 500,
      "probability": 1.0
    },
    "fault_injection": {
      "enabled": true,
      "http_errors": [500, 502, 503],
      "http_error_probability": 0.1
    }
  },
  "tags": ["custom", "testing"],
  "builtin": false
}

Import:

  • Via UI: Use the Profile Exporter component
  • Via CLI: mockforge chaos profile import --file profile.json

API Endpoints

Latency Metrics

GET /api/chaos/metrics/latency

Returns time-series latency data:

{
  "samples": [
    {
      "timestamp": "2024-01-01T12:00:00Z",
      "latency_ms": 150
    }
  ]
}
GET /api/chaos/metrics/latency/stats

Returns aggregated statistics:

{
  "avg_latency_ms": 145.5,
  "min_latency_ms": 100,
  "max_latency_ms": 200,
  "total_requests": 100,
  "p50_ms": 140,
  "p95_ms": 180,
  "p99_ms": 195
}

Profile Management

GET /api/chaos/profiles

List all available profiles.

GET /api/chaos/profiles/{name}

Get a specific profile.

POST /api/chaos/profiles/{name}/apply

Apply a profile to the current configuration.

POST /api/chaos/profiles

Create a custom profile.

DELETE /api/chaos/profiles/{name}

Delete a custom profile.

GET /api/chaos/profiles/{name}/export?format=json

Export a profile.

POST /api/chaos/profiles/import

Import a profile.

Error Pattern Configuration

Update error patterns via the fault injection config endpoint:

PUT /api/chaos/config/faults
{
  "enabled": true,
  "http_errors": [500, 502, 503],
  "error_pattern": {
    "type": "burst",
    "count": 5,
    "interval_ms": 1000
  }
}

CLI Commands

Profile Management

# List all profiles
mockforge chaos profile list

# Apply a profile
mockforge chaos profile apply slow_3g

# Export a profile
mockforge chaos profile export slow_3g --format json --output profile.json

# Import a profile
mockforge chaos profile import --file profile.json

Server Startup

# Start server with a profile applied
mockforge serve --chaos-profile slow_3g --spec openapi.json

Use Cases

Testing Resilience

  1. Apply a “flaky_wifi” profile
  2. Monitor your application’s retry logic
  3. Verify error handling and recovery

Debugging Network Issues

  1. Reproduce reported network conditions
  2. Use the latency graph to identify patterns
  3. Test fixes under controlled conditions

Load Testing Preparation

  1. Create profiles matching production network conditions
  2. Export profiles for CI/CD pipelines
  3. Apply profiles during automated tests

Team Collaboration

  1. Export tested chaos configurations
  2. Share profiles via version control
  3. Standardize testing across environments

Best Practices

Profile Naming

  • Use descriptive names: production_like_network, mobile_edge_conditions
  • Include tags for categorization: ["mobile", "edge", "testing"]
  • Document profile purpose in the description field

Error Pattern Design

  • Start with low probabilities (0.05-0.1) and increase gradually
  • Use burst patterns to test rate limiting and circuit breakers
  • Use sequential patterns to test specific error code handling

Monitoring

  • Always monitor the latency graph when chaos is active
  • Set up alerts for unexpected latency spikes
  • Review statistics regularly to understand impact

Version Control

  • Export profiles before making changes
  • Commit profiles to version control
  • Tag profiles with application versions

Troubleshooting

Latency Graph Not Updating

  • Ensure latency injection is enabled
  • Check that requests are being made to the server
  • Verify the API endpoint is accessible: GET /api/chaos/metrics/latency

Profile Not Applying

  • Verify profile name is correct: mockforge chaos profile list
  • Check server logs for errors
  • Ensure chaos engineering is enabled in configuration

Error Pattern Not Working

  • Verify fault injection is enabled
  • Check error pattern configuration is valid JSON
  • Ensure HTTP error codes are configured: http_errors: [500, 502, 503]

Configuration

Chaos Lab settings can be configured in mockforge.yaml:

observability:
  chaos:
    enabled: true
    latency:
      enabled: true
      fixed_delay_ms: 200
      probability: 0.5
    fault_injection:
      enabled: true
      http_errors: [500, 502, 503]
      http_error_probability: 0.1
      error_pattern:
        type: random
        probability: 0.1

Integration with Test Automation

CI/CD Integration

# Example GitHub Actions workflow
- name: Test with chaos profile
  run: |
    mockforge serve --chaos-profile slow_3g &
    sleep 5
    pytest tests/
    mockforge chaos profile apply none

Test Scripts

#!/bin/bash
# Apply profile and run tests
mockforge chaos profile apply flaky_wifi --base-url http://localhost:3000
npm test
mockforge chaos profile apply none --base-url http://localhost:3000

Performance Considerations

  • Latency metrics are stored in memory (last 100 samples)
  • Profile application is instant (no server restart required)
  • Error pattern evaluation adds minimal overhead (< 1ms per request)
  • Real-time graph updates every 500ms (configurable)

Limitations

  • Latency samples are limited to the last 100 requests
  • Custom profiles are stored in memory (not persisted across restarts)
  • Error patterns apply globally (not per-endpoint)
  • MockAI integration requires MockAI to be enabled

Reality Slider

The Reality Slider is a unified control mechanism that adjusts the realism of your mock environment from simple static stubs to full production-level chaos. It coordinates three key subsystems: Chaos Engineering, Latency Simulation, and MockAI.

Overview

By adjusting a single slider from 1 to 5, you can instantly transform your mock environment to match different testing scenarios without manually configuring each subsystem.

Reality Levels

Level 1: Static Stubs

Use Case: Fast, predictable responses for basic functionality testing

  • Chaos: Disabled
  • Latency: 0ms (instant responses)
  • MockAI: Disabled
  • Best For: Unit tests, rapid prototyping, simple integration checks

Level 2: Light Simulation

Use Case: Minimal realism with basic intelligence

  • Chaos: Disabled
  • Latency: 10-50ms (minimal network delay)
  • MockAI: Basic AI (simple response generation)
  • Best For: Frontend development, basic API testing, quick demos

Level 3: Moderate Realism (Default)

Use Case: Balanced realism for most development scenarios

  • Chaos: 5% error rate, 10% delay probability
  • Latency: 50-200ms (moderate network conditions)
  • MockAI: Full AI enabled (intelligent responses, relationship awareness)
  • Best For: Integration testing, development environments, staging-like behavior

Level 4: High Realism

Use Case: Production-like conditions with increased complexity

  • Chaos: 10% error rate, 20% delay probability
  • Latency: 100-500ms (realistic network conditions)
  • MockAI: Full AI + session state management
  • Best For: Pre-production testing, realistic user flows, stress testing preparation

Level 5: Production Chaos

Use Case: Maximum realism for resilience testing

  • Chaos: 15% error rate, 30% delay probability
  • Latency: 200-2000ms (production-like network conditions)
  • MockAI: Full AI + mutations + advanced features
  • Best For: Chaos engineering, resilience testing, production simulation

Usage

UI Usage

Dashboard

The Reality Slider is available on the Dashboard page:

  1. Navigate to Dashboard in the admin UI
  2. Find the Environment Control section
  3. Use the slider to adjust the reality level (1-5)
  4. Click level indicators for quick selection
  5. View current configuration in the details panel

Configuration Page

For advanced control and preset management:

  1. Navigate to Configuration → Reality Slider
  2. Use the full-featured slider with visual feedback
  3. Manage presets (export/import configurations)
  4. View keyboard shortcuts reference

CLI Usage

Command Line Flag

# Set reality level at startup
mockforge serve --reality-level 5

# With OpenAPI spec
mockforge serve --spec api.yaml --reality-level 3

Environment Variable

# Set via environment variable
export MOCKFORGE_REALITY_LEVEL=4
mockforge serve

# Or inline
MOCKFORGE_REALITY_LEVEL=2 mockforge serve --spec api.yaml

Precedence: CLI flag > Environment variable > Config file > Default (Level 3)

Configuration File

Add to your mockforge.yaml:

reality:
  enabled: true
  level: 3  # 1-5

Or use per-profile configuration:

profiles:
  development:
    reality:
      level: 2
  staging:
    reality:
      level: 4
  production:
    reality:
      level: 5

Keyboard Shortcuts

Quick reality level changes from anywhere in the UI:

ShortcutAction
Ctrl+Shift+1Set to Level 1 (Static Stubs)
Ctrl+Shift+2Set to Level 2 (Light Simulation)
Ctrl+Shift+3Set to Level 3 (Moderate Realism)
Ctrl+Shift+4Set to Level 4 (High Realism)
Ctrl+Shift+5Set to Level 5 (Production Chaos)
Ctrl+Shift+RReset to default (Level 3)
Ctrl+Shift+POpen preset manager (Config page)

Note: Shortcuts are disabled when typing in input fields to avoid conflicts.

Presets

Exporting Presets

Save your current reality configuration for reuse:

  1. Navigate to Configuration → Reality Slider
  2. Click Export Current
  3. Enter a preset name (e.g., “production-chaos”, “staging-realistic”)
  4. Optionally add a description
  5. Click Export Preset

Presets are saved as JSON or YAML files in the workspace presets directory.

Importing Presets

  1. Navigate to Configuration → Reality Slider
  2. Click Import Preset
  3. Select a preset from the list
  4. Click Load to apply

Preset File Format

Presets are stored as JSON or YAML:

{
  "metadata": {
    "name": "production-chaos",
    "description": "Maximum realism for resilience testing",
    "created_at": "2025-01-15T10:30:00Z",
    "version": "1.0"
  },
  "config": {
    "chaos": {
      "enabled": true,
      "error_rate": 0.15,
      "delay_rate": 0.30
    },
    "latency": {
      "base_ms": 200,
      "jitter_ms": 1800
    },
    "mockai": {
      "enabled": true
    }
  }
}

CI/CD Integration

GitHub Actions

env:
  MOCKFORGE_REALITY_LEVEL: 3  # Moderate Realism for tests

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run tests with mock
        run: |
          mockforge serve --reality-level ${{ env.MOCKFORGE_REALITY_LEVEL }} &
          # Run your tests

Docker Compose

services:
  mockforge:
    environment:
      - MOCKFORGE_REALITY_LEVEL=${MOCKFORGE_REALITY_LEVEL:-3}

API Reference

Get Current Reality Level

GET /__mockforge/reality/level

Response:

{
  "level": 3,
  "level_name": "Moderate Realism",
  "description": "Some chaos, moderate latency, full intelligence",
  "chaos": {
    "enabled": true,
    "error_rate": 0.05,
    "delay_rate": 0.10
  },
  "latency": {
    "base_ms": 50,
    "jitter_ms": 150
  },
  "mockai": {
    "enabled": true
  }
}

Set Reality Level

PUT /__mockforge/reality/level
Content-Type: application/json

{
  "level": 5
}

Use Cases

Development Workflow

  1. Start Development: Level 2 (Light Simulation)

    • Fast responses for rapid iteration
    • Basic AI for realistic data
  2. Integration Testing: Level 3 (Moderate Realism)

    • Some chaos to catch error handling
    • Realistic latency for network-aware code
  3. Pre-Production: Level 4 (High Realism)

    • Production-like conditions
    • Full feature set enabled
  4. Resilience Testing: Level 5 (Production Chaos)

    • Maximum chaos for stress testing
    • Simulate worst-case scenarios

Testing Scenarios

Unit Tests

# Fast, predictable responses
MOCKFORGE_REALITY_LEVEL=1 npm test

Integration Tests

# Moderate realism
MOCKFORGE_REALITY_LEVEL=3 npm test

E2E Tests

# High realism for production-like testing
MOCKFORGE_REALITY_LEVEL=4 npm test

Chaos Engineering

# Maximum chaos for resilience testing
MOCKFORGE_REALITY_LEVEL=5 npm test

Best Practices

  1. Start Low, Increase Gradually: Begin with Level 1-2 for development, increase as you approach production
  2. Use Presets: Save common configurations for different environments
  3. CI/CD Integration: Set appropriate levels for different test stages
  4. Monitor Impact: Watch metrics as you change levels to understand the impact
  5. Document Your Levels: Use preset descriptions to document when to use each configuration

Troubleshooting

Level Changes Not Applying

  • Check that the reality slider is enabled in configuration
  • Verify API endpoint is accessible: curl http://localhost:9080/__mockforge/reality/level
  • Check server logs for errors

Shortcuts Not Working

  • Ensure you’re not typing in an input field
  • Check browser console for JavaScript errors
  • Verify shortcuts are enabled (disabled in compact mode)

Presets Not Loading

  • Verify preset file format (JSON or YAML)
  • Check file permissions
  • Ensure preset path is correct
  • Review server logs for import errors

Data Scenario Marketplace

The Data Scenario Marketplace allows you to discover, install, and use community-built realistic mock scenarios with one-click import functionality. Share your scenarios with the community or use pre-built scenarios for common use cases.

Overview

Scenarios are complete mock system configurations that include:

  • MockForge configuration files (config.yaml)
  • OpenAPI specifications
  • Protocol-specific fixtures
  • Example data files
  • Documentation

Quick Start

Install a Scenario

# Install from local path
mockforge scenario install ./examples/scenarios/ecommerce-store

# Install from URL
mockforge scenario install https://example.com/scenarios/ecommerce-store.zip

# Install from Git repository
mockforge scenario install https://github.com/user/scenarios#main:ecommerce-store

# Install from registry
mockforge scenario install ecommerce-store

Apply Scenario to Workspace

# Apply installed scenario to current directory
mockforge scenario use ecommerce-store

# This copies:
# - config.yaml
# - openapi.json
# - fixtures/
# - examples/

Start the Server

mockforge serve --config config.yaml

Available Commands

Install

Install a scenario from various sources:

mockforge scenario install <source> [--force] [--skip-validation] [--checksum <sha256>]

Sources:

  • Local path: ./scenarios/my-scenario
  • URL: https://example.com/scenario.zip
  • Git: https://github.com/user/repo#main:scenarios/my-scenario
  • Registry: ecommerce-store or [email protected]

Options:

  • --force: Force reinstall even if scenario exists
  • --skip-validation: Skip package validation
  • --checksum: Expected SHA-256 checksum (for URL sources)

List

List all installed scenarios:

mockforge scenario list [--detailed]

Info

Show detailed information about an installed scenario:

mockforge scenario info <name> [--version <version>]

Use

Apply a scenario to the current workspace:

mockforge scenario use <name> [--version <version>]

This copies scenario files to the current directory, allowing you to start using the scenario immediately.

Search for scenarios in the registry:

mockforge scenario search <query> [--category <category>] [--limit <n>]

Publish

Publish your scenario to the marketplace. Name, version, description, category, and tags are read from the package’s scenario.yaml:

mockforge scenario publish ./my-scenario

Scenario Structure

A scenario package must follow this structure:

my-scenario/
├── scenario.yaml          # Scenario metadata
├── config.yaml            # MockForge configuration
├── openapi.json           # OpenAPI specification
├── fixtures/              # Protocol-specific fixtures
│   ├── http/
│   ├── grpc/
│   └── websocket/
├── examples/              # Example data files
├── README.md              # Documentation
└── CHANGELOG.md           # Version history

scenario.yaml

name: ecommerce-store
version: 1.0.0
description: Complete e-commerce API mock
author: John Doe
category: ecommerce
tags:
  - api
  - rest
  - ecommerce
  - shopping
dependencies: []

Marketplace Features

Tags and Categories

Scenarios are organized by:

  • Categories: ecommerce, fintech, healthcare, iot, etc.
  • Tags: api, rest, grpc, websocket, etc.
  • Ratings: Community ratings and reviews
  • Versioning: Semantic versioning support

Ratings and Reviews

Rate and review scenarios:

# Rate and review a scenario
mockforge scenario review submit <name> --rating 5 --comment "Great scenario!" --reviewer <username>

# View reviews
mockforge scenario review list <name>

Versioning

Scenarios use semantic versioning:

# Install specific version
mockforge scenario install [email protected]

# Install latest version
mockforge scenario install ecommerce-store@latest

# Update to latest
mockforge scenario update ecommerce-store

Domain-Specific Packs

E-commerce

Complete e-commerce API scenarios:

mockforge scenario install ecommerce-store

Includes:

  • Product catalog
  • Shopping cart
  • Order management
  • Payment processing
  • User accounts

Fintech

Financial services scenarios:

mockforge scenario install fintech-banking

Includes:

  • Account management
  • Transactions
  • Payments
  • Cards
  • Loans

Healthcare

Healthcare API scenarios:

mockforge scenario install healthcare-api

Includes:

  • Patient records
  • Appointments
  • Prescriptions
  • Medical devices

IoT

IoT device scenarios:

mockforge scenario install iot-devices

Includes:

  • Device management
  • Sensor data
  • Commands
  • Telemetry

Integration with VBR and MockAI

Scenarios automatically integrate with VBR and MockAI:

VBR Integration

Scenarios can include VBR entity definitions:

# scenario.yaml
vbr_entities:
  - name: users
    schema: ./schemas/user.json
    seed_data: ./data/users.json

MockAI Integration

Scenarios can include MockAI rules:

# scenario.yaml
mockai_rules:
  - endpoint: "/users"
    rules: ./rules/users.json

API Endpoints

Marketplace API

GET /api/scenarios/marketplace?category=ecommerce&tags=api

List scenarios from marketplace.

GET /api/scenarios/marketplace/{name}

Get scenario details.

POST /api/scenarios/marketplace/{name}/install

Install scenario from marketplace.

Local Scenarios

GET /api/scenarios/local

List installed scenarios.

GET /api/scenarios/local/{name}

Get installed scenario details.

POST /api/scenarios/local/{name}/use

Apply scenario to workspace.

Use Cases

Quick Prototyping

Start with a pre-built scenario:

# Install e-commerce scenario
mockforge scenario install ecommerce-store

# Apply to workspace
mockforge scenario use ecommerce-store

# Start server
mockforge serve --config config.yaml

Team Sharing

Share scenarios within your team:

# Publish to internal registry
mockforge scenario publish ./internal-api \
  --registry "https://internal-registry.example.com"

Community Contribution

Contribute scenarios to the community:

# Publish to the default registry
mockforge scenario publish ./my-awesome-scenario

Best Practices

  1. Document Well: Include comprehensive README and examples
  2. Version Properly: Use semantic versioning
  3. Test Thoroughly: Ensure scenarios work out of the box
  4. Tag Appropriately: Use relevant tags and categories
  5. Keep Updated: Maintain scenarios with bug fixes and improvements

Troubleshooting

Installation Fails

  • Verify scenario structure is correct
  • Check file permissions
  • Review scenario.yaml for errors

Scenario Not Working

  • Check MockForge version compatibility
  • Verify all dependencies are installed
  • Review scenario documentation

Marketplace Connection Issues

  • Verify network connectivity
  • Check marketplace URL is correct
  • Review authentication credentials

Mock-Oriented Development (MOD)

Pillars: [DevX][Reality][Contracts]

Mock-Oriented Development (MOD) is a software development methodology that places mocks at the center of the development workflow. Just as Test-Driven Development (TDD) revolutionized testing, and Infrastructure as Code (IaC) transformed DevOps, MOD transforms how we build and integrate APIs.

What is MOD?

MOD is not just about using mocks—it’s about thinking mock-first, designing with mocks, and building confidence through realistic simulation.

The MOD Manifesto

  1. Mocks are not afterthoughts — They are first-class citizens in your development process
  2. Design with mocks — Use mocks to explore API designs before implementation
  3. Reality matters — Mocks should feel indistinguishable from real backends
  4. Contracts are sacred — Mocks enforce and validate API contracts
  5. Iterate fearlessly — Mocks enable rapid iteration without breaking dependencies
  6. Collaborate through mocks — Teams work in parallel using shared mock definitions

Why MOD?

The Problem MOD Solves

Traditional development workflows create bottlenecks:

  • Frontend teams wait for backend APIs to be ready
  • Backend teams build APIs in isolation without early feedback
  • Integration happens late, revealing design flaws when changes are expensive
  • Testing relies on fragile, hard-to-maintain fixtures
  • Documentation is outdated or missing

The MOD Solution

MOD flips the script:

  • Frontend teams start immediately with realistic mocks
  • Backend teams validate designs through mock-driven API reviews
  • Integration happens continuously through shared mock contracts
  • Testing uses living, evolving mock scenarios
  • Documentation is generated from mock definitions

MOD vs. Other Methodologies

MOD vs. TDD (Test-Driven Development)

AspectTDDMOD
FocusTests drive implementationMocks drive design and integration
WhenDuring implementationBefore and during implementation
ScopeUnit/component levelSystem/integration level
ArtifactTest codeMock definitions + contracts

MOD complements TDD: Use TDD for implementation, MOD for integration.

MOD vs. BDD (Behavior-Driven Development)

AspectBDDMOD
FocusBehavior specificationsAPI contracts and interactions
LanguageNatural language (Gherkin)API schemas (OpenAPI, gRPC)
ScopeFeature behaviorSystem integration
ArtifactFeature filesMock scenarios

MOD complements BDD: Use BDD for features, MOD for APIs.

MOD vs. IaC (Infrastructure as Code)

AspectIaCMOD
FocusInfrastructure provisioningAPI simulation
DomainDevOps/InfrastructureDevelopment/Integration
ArtifactTerraform/CloudFormationMock configurations
LifecycleDeploy/manage infrastructureSimulate/validate APIs

MOD is like IaC for APIs: Version-controlled, reproducible, declarative.

MOD Principles

1. Mock-First Design

Start with mocks, not implementations.

Before writing backend code, create mock APIs that define:

  • Request/response schemas
  • Error scenarios
  • Edge cases
  • Performance characteristics

Benefits:

  • Early validation of API design
  • Frontend can start immediately
  • Clear contract definition
  • Stakeholder feedback before implementation

2. Contract-Driven Development

Contracts are the source of truth.

Define API contracts (OpenAPI, gRPC, GraphQL) first:

  • Generate mocks from contracts
  • Validate implementations against contracts
  • Detect contract drift automatically
  • Version contracts explicitly

Benefits:

  • Single source of truth
  • Automatic validation
  • Breaking change detection
  • Clear API evolution

3. Reality Progression

Gradually increase mock realism.

Start with simple mocks, then add:

  • Realistic data generation
  • Behavioral patterns
  • Error scenarios
  • Performance characteristics

Benefits:

  • Early development with simple mocks
  • Gradual complexity as needed
  • Production-like testing when ready
  • Smooth transition to real backend

4. Scenario-Driven Testing

Test with scenarios, not fixtures.

Use scenarios that define:

  • Multi-step workflows
  • State transitions
  • Error paths
  • Edge cases

Benefits:

  • Realistic test flows
  • Reusable scenarios
  • Easy scenario updates
  • Living test documentation

5. Continuous Integration

Mocks are part of CI/CD.

Integrate mocks into:

  • Development workflows
  • CI/CD pipelines
  • Testing strategies
  • Documentation generation

Benefits:

  • Automated validation
  • Early error detection
  • Consistent environments
  • Up-to-date documentation

MOD Workflow

1. Design Phase

Define Contract → Create Mock → Review with Team → Iterate
  1. Define API contract (OpenAPI, gRPC, etc.)
  2. Generate initial mock from contract
  3. Review mock responses with team
  4. Iterate on design based on feedback

2. Development Phase

Frontend: Use Mock → Backend: Implement Contract → Integration: Validate
  1. Frontend team uses mock for development
  2. Backend team implements to match contract
  3. Integration validates implementation against mock

3. Testing Phase

Unit Tests → Integration Tests → E2E Tests (all with mocks)
  1. Unit tests use mock responses
  2. Integration tests use mock services
  3. E2E tests use mock backends

4. Review Phase

PR Review → Contract Validation → Mock Comparison → Approval
  1. PR includes contract changes
  2. Validate contract changes
  3. Compare mock vs. implementation
  4. Approve if contract matches

Getting Started with MOD

1. Initialize MOD Project

# Initialize a new MOD project
mockforge mod init --name my-api-project

# This creates:
# - mockforge.yaml (MOD configuration)
# - contracts/ (API contract definitions)
# - mocks/ (Mock definitions)
# - scenarios/ (Test scenarios)
# - personas/ (Persona definitions)

2. Define Your First Contract

# contracts/users-api.yaml
openapi: 3.0.0
info:
  title: Users API
  version: 1.0.0
paths:
  /api/users/{id}:
    get:
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: User details
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  email:
                    type: string

3. Generate Mock from Contract

# Generate mock from OpenAPI contract
mockforge generate --spec contracts/users-api.yaml --output mocks/

4. Use Mock in Development

// Frontend code uses mock
import { useUser } from './generated/clients/react';

function UserProfile({ userId }) {
  const { data, loading } = useUser(userId);
  // ...
}

MOD Folder Structures

Solo Developer

my-project/
├── mockforge.yaml
├── contracts/
│   ├── api.yaml
│   └── schemas/
├── mocks/
│   └── responses/
├── scenarios/
│   └── user-journeys.yaml
├── personas/
│   └── default.yaml
└── README.md

Small Team (2-5 developers)

my-api/
├── mockforge.yaml
├── contracts/
│   ├── v1/
│   │   ├── openapi.yaml
│   │   └── schemas/
│   └── v2/
│       ├── openapi.yaml
│       └── schemas/
├── mocks/
│   ├── endpoints/
│   │   ├── users.yaml
│   │   └── orders.yaml
│   └── scenarios/
│       └── checkout-flow.yaml
├── scenarios/
│   ├── happy-paths/
│   ├── error-paths/
│   └── edge-cases/
└── personas/
    ├── customers.yaml
    └── admins.yaml

Large Team (6+ developers)

monorepo/
├── services/
│   ├── auth-service/
│   │   ├── contracts/
│   │   ├── mocks/
│   │   └── scenarios/
│   ├── payment-service/
│   │   ├── contracts/
│   │   ├── mocks/
│   │   └── scenarios/
│   └── order-service/
│       ├── contracts/
│       ├── mocks/
│       └── scenarios/
├── shared/
│   ├── contracts/  # Shared contracts
│   └── personas/   # Shared personas
└── mockforge.yaml  # Root configuration

MOD Patterns

Pattern 1: Contract-First API Design

  1. Design contract (OpenAPI)
  2. Generate mock
  3. Review with team
  4. Implement backend
  5. Validate against contract

Pattern 2: Scenario-Driven Development

  1. Define scenario (user journey)
  2. Create mocks for scenario
  3. Implement frontend using mocks
  4. Implement backend to match scenario
  5. Test end-to-end with scenario

Pattern 3: Progressive Realism

  1. Start with simple mocks (static responses)
  2. Add realistic data (faker generation)
  3. Add behavioral patterns (personas)
  4. Add error scenarios (chaos)
  5. Blend with real backend (reality continuum)

MOD Success Metrics

Track MOD effectiveness:

  • Time to First Integration — How quickly can teams integrate?
  • Contract Drift — How often do implementations diverge from contracts?
  • Frontend Blocking — How often is frontend blocked by backend?
  • API Review Time — How long do API reviews take?
  • Integration Bugs — How many bugs are found during integration?

Best Practices

  1. Start Early: Create mocks before implementation
  2. Version Contracts: Use semantic versioning for contracts
  3. Keep Mocks Updated: Update mocks as contracts evolve
  4. Use Scenarios: Test with scenarios, not just fixtures
  5. Document Decisions: Document why mocks are configured certain ways

Virtual Backend Reality (VBR) Engine

Experimental. This feature ships in MockForge but is early: the engine and the mockforge vbr commands work, but it is not yet enabled from mockforge serve (there is no --vbr-enabled flag or vbr: config key). Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

The Virtual Backend Reality (VBR) Engine provides a virtual “database” layer that automatically generates CRUD operations from OpenAPI specifications. It enables stateful mocking with relationship management, data persistence, and realistic data generation.

Overview

The VBR Engine transforms MockForge from a simple request/response mock server into a stateful backend simulator. Instead of returning static responses, VBR maintains a virtual database that supports:

  • Automatic CRUD operations from OpenAPI specs
  • Relationship mapping (1:N and N:N)
  • Data persistence across server restarts
  • State snapshots for point-in-time recovery
  • Realistic ID generation with customizable patterns

Quick Start

From OpenAPI Specification

VBR is not enabled from mockforge serve (there is no --vbr-enabled flag or vbr: config key). Use the standalone mockforge vbr commands instead:

# Import entity definitions from an OpenAPI spec
mockforge vbr import openapi api.yaml --output ./entities

# Start the standalone VBR API server (default prefix /vbr-api)
mockforge vbr serve --port 3000 --storage sqlite --db-path ./vbr-data/vbr.db

Programmatic Usage

#![allow(unused)]
fn main() {
use mockforge_vbr::VbrEngine;

// Create engine from OpenAPI spec
let (engine, result) = VbrEngine::from_openapi_file(config, "./api-spec.yaml").await?;

// Or create manually
let mut engine = VbrEngine::new(config).await?;
}

Features

Automatic CRUD Generation

VBR automatically detects CRUD operations from your OpenAPI specification:

  • GET /users → List all users
  • GET /users/{id} → Get user by ID
  • POST /users → Create new user
  • PUT /users/{id} → Update user
  • DELETE /users/{id} → Delete user

Primary keys are auto-detected (fields named id, uuid, etc.), and foreign keys are inferred from field names ending in _id.

Relationship Mapping

One-to-Many (1:N)

VBR automatically detects foreign key relationships:

# OpenAPI spec
components:
  schemas:
    User:
      properties:
        id: { type: integer }
        name: { type: string }
    
    Post:
      properties:
        id: { type: integer }
        user_id: { type: integer }  # Foreign key detected
        title: { type: string }

This creates a relationship where one User can have many Posts. Access related resources:

# Get all posts for a user
GET /vbr-api/users/1/posts

Many-to-Many (N:N)

Define many-to-many relationships explicitly:

#![allow(unused)]
fn main() {
use mockforge_vbr::ManyToManyDefinition;

let m2m = ManyToManyDefinition::new("User".to_string(), "Role".to_string());
schema.with_many_to_many(m2m);
}

This creates a junction table automatically (e.g., user_role) and enables:

# Get all roles for a user
GET /vbr-api/users/1/roles

# Get all users with a role
GET /vbr-api/roles/1/users

Data Seeding

Seed your virtual database with initial data:

From File

# Seed from JSON file
mockforge vbr seed seed-data.json

# Seed from YAML file, only the User entity
mockforge vbr seed seed-data.yaml --entity User

Seed file format:

{
  "users": [
    {"id": 1, "name": "Alice", "email": "[email protected]"},
    {"id": 2, "name": "Bob", "email": "[email protected]"}
  ],
  "posts": [
    {"id": 1, "user_id": 1, "title": "First Post"},
    {"id": 2, "user_id": 1, "title": "Second Post"}
  ]
}

Programmatic Seeding

#![allow(unused)]
fn main() {
// Seed a single entity
engine.seed_entity("users", vec![
    json!({"name": "Alice", "email": "[email protected]"}),
    json!({"name": "Bob", "email": "[email protected]"}),
]).await?;

// Seed all entities from file
engine.seed_from_file("./seed-data.json").await?;

// Clear entity data
engine.clear_entity("users").await?;

// Clear all data
engine.reset().await?;
}

ID Generation

VBR supports multiple ID generation strategies:

Pattern-Based IDs

#![allow(unused)]
fn main() {
.with_auto_generation("id", AutoGenerationRule::Pattern("USR-{increment:06}".to_string()))
}

Template variables:

  • {increment} or {increment:06} - Auto-incrementing with optional padding
  • {timestamp} - Unix timestamp
  • {random} or {random:8} - Random alphanumeric (default length 8)
  • {uuid} - UUID v4

Realistic IDs (Stripe-style)

#![allow(unused)]
fn main() {
.with_auto_generation("id", AutoGenerationRule::Realistic {
    prefix: "cus".to_string(),
    length: 14
})
}

Generates IDs like: cus_abc123def456

State Snapshots

Create point-in-time snapshots of your virtual database:

Create Snapshot

# Via CLI
mockforge vbr snapshot create initial --description "Initial state"

# Via API
curl -X POST http://localhost:3000/vbr-api/snapshots \
  -H "Content-Type: application/json" \
  -d '{"name": "initial", "description": "Initial state"}'

Restore Snapshot

# Via CLI
mockforge vbr snapshot restore initial

# Via API
curl -X POST http://localhost:3000/vbr-api/snapshots/initial/restore

List Snapshots

# Via CLI
mockforge vbr snapshot list

# Via API
curl http://localhost:3000/vbr-api/snapshots

Delete Snapshot

# Via CLI
mockforge vbr snapshot delete initial

# Via API
curl -X DELETE http://localhost:3000/vbr-api/snapshots/initial

Time-Based Expiry

Configure records to expire after a certain time:

vbr:
  entities:
    - name: sessions
      ttl_seconds: 3600  # Expire after 1 hour
      aging_enabled: true

Records older than the TTL are automatically removed.

Storage Backends

VBR supports multiple storage backends:

Persistent storage with full SQL support:

vbr:
  backend: "sqlite"
  storage_path: "./vbr-data.db"

Advantages:

  • Full SQL query support
  • ACID transactions
  • Efficient for large datasets
  • Easy to inspect with SQL tools

JSON

File-based storage for simple use cases:

vbr:
  backend: "json"
  storage_path: "./vbr-data.json"

Advantages:

  • Human-readable
  • Easy to version control
  • Simple backup/restore

In-Memory

Fast, non-persistent storage:

vbr:
  backend: "memory"

Advantages:

  • Fastest performance
  • No disk I/O
  • Perfect for testing

Note: Data is lost on server restart.

API Endpoints

VBR automatically creates REST API endpoints for all entities:

Entity Operations

# List all entities
GET /vbr-api/{entity}

# Get entity by ID
GET /vbr-api/{entity}/{id}

# Create entity
POST /vbr-api/{entity}
Content-Type: application/json

{
  "name": "Alice",
  "email": "[email protected]"
}

# Update entity
PUT /vbr-api/{entity}/{id}
Content-Type: application/json

{
  "name": "Alice Updated"
}

# Delete entity
DELETE /vbr-api/{entity}/{id}

Relationship Operations

# Get related entities (1:N)
GET /vbr-api/{entity}/{id}/{relationship}

# Get related entities (N:N)
GET /vbr-api/{entity}/{id}/{relationship}

Snapshot Operations

# Create snapshot
POST /vbr-api/snapshots
Content-Type: application/json

{
  "name": "snapshot1",
  "description": "Optional description"
}

# List snapshots
GET /vbr-api/snapshots

# Get snapshot metadata
GET /vbr-api/snapshots/{name}

# Restore snapshot
POST /vbr-api/snapshots/{name}/restore

# Delete snapshot
DELETE /vbr-api/snapshots/{name}

Database Management

# Reset entire database
POST /vbr-api/reset

# Reset specific entity
POST /vbr-api/reset/{entity}

Configuration

Full Configuration Example

vbr:
  enabled: true
  
  # OpenAPI spec for auto-generation
  openapi_spec: "./api.yaml"
  
  # Storage backend
  backend: "sqlite"  # sqlite, json, memory
  storage_path: "./vbr-data"
  
  # Entity configuration
  entities:
    - name: users
      primary_key: "id"
      auto_generation:
        id: "pattern:USR-{increment:06}"
      ttl_seconds: null  # No expiry
      aging_enabled: false
    
    - name: sessions
      primary_key: "id"
      ttl_seconds: 3600  # Expire after 1 hour
      aging_enabled: true
  
  # Relationships
  relationships:
    - type: "one_to_many"
      from: "users"
      to: "posts"
      foreign_key: "user_id"
    
    - type: "many_to_many"
      from: "users"
      to: "roles"
      junction_table: "user_role"
  
  # Snapshot configuration
  snapshots:
    enabled: true
    directory: "./snapshots"
    max_snapshots: 10

Use Cases

Development Environment

Create a realistic development environment without a real database:

vbr:
  enabled: true
  backend: "sqlite"
  openapi_spec: "./api.yaml"

Integration Testing

Use VBR for integration tests with deterministic data:

#![allow(unused)]
fn main() {
// Setup
let engine = VbrEngine::from_openapi_file(config, "./api.yaml").await?;
engine.seed_from_file("./test-data.json").await?;

// Run tests
// ...

// Cleanup
engine.reset().await?;
}

Demo Environments

Create snapshots for consistent demo environments:

# Setup demo data
mockforge vbr seed demo-data.json

# Create snapshot
mockforge vbr snapshot create demo

# Later, restore for consistent demos
mockforge vbr snapshot restore demo

Best Practices

  1. Use SQLite for Production: SQLite provides the best balance of performance and features
  2. Seed Initial Data: Use seed files for consistent starting states
  3. Create Snapshots: Save important states for quick restoration
  4. Configure TTL: Use time-based expiry for session-like data
  5. Version Control Seed Files: Keep seed data in version control
  6. Use Realistic IDs: Pattern-based IDs make data look more realistic

Troubleshooting

Primary Key Not Detected

If VBR doesn’t detect your primary key, specify it explicitly:

vbr:
  entities:
    - name: users
      primary_key: "user_id"  # Explicit primary key

Foreign Key Not Detected

If foreign key relationships aren’t detected, define them explicitly:

vbr:
  relationships:
    - type: "one_to_many"
      from: "users"
      to: "posts"
      foreign_key: "author_id"  # Custom foreign key name

Snapshot Restore Fails

Ensure the snapshot directory exists and has write permissions:

mkdir -p ./snapshots
chmod 755 ./snapshots

Reality Profiles Marketplace

Experimental. This feature ships in MockForge but is early: mockforge reality-profile installs the four built-in packs or a local file, but there is no remote marketplace yet and applying a pack does not yet change runtime behavior. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Reality]

The Reality Profiles Marketplace provides pre-tuned “realism packs” that bundle personas, scenarios, chaos rules, latency curves, error distributions, data mutation behaviors, and protocol behaviors into ready-to-use packages. Think of them as MockForge’s “Kubernetes Operators” moment—reusable ops-level behaviors.

Overview

Reality profile packs are complete configurations that simulate real-world scenarios for specific domains. Instead of manually configuring latency curves, error distributions, and behavioral patterns, you can install a pack that provides all of this out of the box.

Available Packs

E-Commerce Peak Season Pack

Simulates high-load e-commerce scenarios with:

  • Increased latency during peak hours (300ms mean, up to 2000ms)
  • Cart abandonment patterns (cart value decreases over time)
  • Inventory depletion behaviors (quantity decreases under load)
  • Seasonal purchase patterns

Install:

mockforge reality-profile install ecommerce-peak-season

Use Case: Testing your frontend’s resilience during Black Friday, Cyber Monday, or other high-traffic events.

Fintech Fraud Pack

Simulates financial services scenarios with:

  • Fraud detection triggers (suspicious transaction patterns)
  • Transaction declines (card declined, insufficient funds)
  • Risk scoring (high-risk vs low-risk customer segments)
  • Compliance behaviors (KYC checks, AML flags)

Install:

mockforge reality-profile install fintech-fraud

Use Case: Testing fraud detection systems, payment flows, and compliance workflows.

Healthcare HL7/Insurance Edge Cases Pack

Simulates healthcare scenarios with:

  • HL7 message patterns (ADT, ORU, MDM message types)
  • Insurance edge cases (pre-authorization failures, coverage gaps)
  • Patient data patterns (HIPAA-compliant test data)
  • Medical device integration (device disconnections, data bursts)

Install:

mockforge reality-profile install healthcare-hl7

Use Case: Testing HL7 integrations, insurance workflows, and medical device connectivity.

IoT Device Fleet Chaos Pack

Simulates IoT scenarios with:

  • Device disconnections (random disconnects, network failures)
  • Message bursts (sudden spikes in telemetry data)
  • Protocol behaviors (MQTT, CoAP, WebSocket patterns)
  • Edge computing patterns (offline mode, sync conflicts)

Install:

mockforge reality-profile install iot-fleet-chaos

Use Case: Testing IoT platforms, device management systems, and edge computing scenarios.

Installing Packs

From Pre-built Packs

# List available packs
mockforge reality-profile list

# Install a pack
mockforge reality-profile install <pack-name>

# Examples
mockforge reality-profile install ecommerce-peak-season
mockforge reality-profile install fintech-fraud
mockforge reality-profile install healthcare-hl7
mockforge reality-profile install iot-fleet-chaos

From Custom Paths

You can also install packs from local files or URLs:

# From local file
mockforge reality-profile install ./my-custom-pack.yaml

# From URL
mockforge reality-profile install https://example.com/packs/custom-pack.yaml

Pack Structure

Each reality profile pack includes:

1. Personas

Pre-configured personas with traits matching the domain:

  • E-commerce: premium-customer, bargain-hunter, cart-abandoner
  • Fintech: high-risk-user, vip-customer, fraud-suspect
  • Healthcare: new-patient, chronic-care-patient, emergency-case
  • IoT: smart-home-owner, industrial-operator, fleet-manager

2. Scenarios

Ready-to-use scenarios for common workflows:

  • E-commerce: peak-season-checkout, cart-abandonment-flow, inventory-depletion
  • Fintech: fraud-detection-flow, payment-decline-scenario, kyc-verification
  • Healthcare: patient-admission, insurance-claim-processing, device-alert
  • IoT: device-onboarding, telemetry-burst, firmware-update-failure

3. Chaos Rules

Pre-configured chaos engineering rules:

  • Latency spikes during peak hours
  • Error rate increases under load
  • Network partition simulations
  • Resource exhaustion patterns

4. Latency Curves

Realistic latency distributions:

  • Normal distributions for typical traffic
  • Exponential distributions for burst scenarios
  • Custom curves for specific endpoints

5. Error Distributions

Realistic error patterns:

  • 5xx errors under load
  • 4xx errors for invalid requests
  • Rate limiting (429) during peak
  • Timeout errors (504) for slow endpoints

6. Data Mutation Behaviors

Dynamic data changes:

  • Inventory depletion over time
  • Cart abandonment patterns
  • Account balance changes
  • Device state transitions

7. Protocol Behaviors

Protocol-specific behaviors:

  • REST: HTTP method patterns, status code distributions
  • WebSocket: Connection lifecycle, message patterns
  • MQTT: Topic subscriptions, QoS levels
  • gRPC: Streaming patterns, error codes

Using Packs in Your Workspace

After installing a pack, it’s available for use in your workspace configuration:

# mockforge.yaml
reality:
  profiles:
    - name: ecommerce-peak-season
      enabled: true
      # Pack-specific configuration
      peak_hours:
        start: "09:00"
        end: "17:00"
      load_multiplier: 1.5  # 50% more load during peak

Creating Custom Packs

You can create your own reality profile packs:

1. Create Pack Manifest

# my-custom-pack.yaml
name: my-custom-pack
version: 1.0.0
title: My Custom Reality Pack
description: Custom reality profile for my domain
domain: custom
author: My Team

tags:
  - custom
  - internal

# Latency curves
latency_curves:
  - protocol: rest
    distribution: normal
    params:
      mean: 200.0
      std_dev: 50.0
    base_ms: 200
    endpoint_patterns:
      - "/api/custom/*"
    jitter_ms: 25
    min_ms: 100
    max_ms: 1000

# Error distributions
error_distributions:
  - endpoint_pattern: "/api/custom/*"
    error_codes: [500, 503]
    probabilities: [0.05, 0.02]
    pattern:
      type: random
      probability: 0.07

# Data mutation behaviors
data_mutation_behaviors:
  - field_pattern: "body.value"
    mutation_type: increment
    rate: 0.1
    params:
      increment_by: 1
      max_value: 100

2. Install Custom Pack

mockforge reality-profile install ./my-custom-pack.yaml

Pack Configuration

Packs can be configured per-workspace:

reality:
  profiles:
    - name: ecommerce-peak-season
      enabled: true
      config:
        # Override pack defaults
        peak_hours:
          start: "10:00"
          end: "18:00"
        load_multiplier: 2.0
        error_rate_multiplier: 1.5

Integration with Other Features

Reality profile packs integrate seamlessly with:

  • Smart Personas: Packs include personas that work with the pack’s scenarios
  • Scenarios: Pre-built scenarios use the pack’s behavioral patterns
  • Chaos Lab: Pack chaos rules integrate with your chaos experiments
  • Reality Continuum: Packs work with blend ratios and reality levels
  • Time Travel: Pack behaviors respect virtual time settings

Best Practices

  1. Start with Pre-built Packs: Use existing packs before creating custom ones
  2. Combine Packs: You can enable multiple packs and combine their behaviors
  3. Customize Gradually: Start with defaults, then customize as needed
  4. Version Control: Keep pack configurations in version control
  5. Team Sharing: Share custom packs via Git or internal registry

Examples

E-Commerce Peak Season Testing

# Install pack
mockforge reality-profile install ecommerce-peak-season

# Configure workspace
# mockforge.yaml
reality:
  profiles:
    - name: ecommerce-peak-season
      enabled: true
      config:
        peak_hours:
          start: "00:00"  # Black Friday - all day peak
          end: "23:59"
        load_multiplier: 3.0  # 3x normal load

Fintech Fraud Testing

# Install pack
mockforge reality-profile install fintech-fraud

# Use in scenarios
scenarios:
  - name: fraud-detection-test
    persona: high-risk-user
    reality_profile: fintech-fraud
    steps:
      - endpoint: POST /api/transactions
        expected_fraud_score: "> 0.7"

Troubleshooting

Pack Not Found

If a pack isn’t found, check:

  • Pack name spelling
  • Pack is installed: mockforge reality-profile list
  • Pack version compatibility

Conflicts Between Packs

If multiple packs conflict:

  • Check endpoint pattern overlaps
  • Adjust pack priorities
  • Disable conflicting packs
  • Create custom pack combining needed features

ForgeConnect SDK

Experimental. This feature ships in MockForge but is early: the browser SDK (sdk/browser, v0.1) and DevTools extension exist in the repository, but framework sub-path imports (/react, /vue, /next) are not published yet and the extension is not listed in browser stores. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

ForgeConnect SDK provides browser extension and framework SDKs for capturing network traffic, auto-generating mocks, and integrating with popular frontend frameworks. Develop and test frontend applications with seamless mock integration.

Overview

ForgeConnect includes:

  • Browser Extension: Capture network traffic and create mocks automatically
  • Browser SDK: JavaScript/TypeScript SDK for framework integration
  • Auto-Mock Generation: Automatically create mocks for unhandled requests
  • Framework Adapters: React, Vue, Angular, Next.js support
  • Auth Passthrough: Support for OAuth flows and authentication

Quick Start

Install Browser Extension

  1. Install from Chrome Web Store or Firefox Add-ons
  2. Open browser DevTools
  3. Navigate to “MockForge” tab
  4. Connect to MockForge server

Install Browser SDK

npm install @mockforge/forgeconnect

Basic Usage

import { ForgeConnect } from '@mockforge/forgeconnect';

// Initialize ForgeConnect
const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  autoMock: true
});

// Start intercepting requests
forgeConnect.start();

Browser Extension

Features

  • Request Capture: Automatically capture all network requests
  • Mock Creation: Create mocks from captured requests with one click
  • DevTools Integration: Full DevTools panel with React UI
  • Auto-Discovery: Automatically discover MockForge server
  • Request Filtering: Filter requests by URL, method, status
  • Live Response Modification: Modify responses on-the-fly in DevTools
  • Persona/Scenario Toggling: Switch personas and scenarios directly from DevTools
  • Reverse Injection: Automatically inject mocks back into workspace
  • Snapshot Diff: Compare mock behavior between environments

DevTools Panel

The ForgeConnect extension adds a dedicated “MockForge” tab to your browser’s DevTools with the following features:

Request Capture Tab

  • Live Request Monitoring: See all fetch/XHR requests in real-time
  • Request Details: View request method, URL, headers, body, and response
  • Filter & Search: Filter requests by URL pattern, method, or status code
  • One-Click Mock Creation: Click “Mock this endpoint” to create a mock from any request

Mocks Management Tab

  • View All Mocks: See all mocks in your MockForge workspace
  • Edit Mocks: Modify mock responses directly in DevTools
  • Delete Mocks: Remove mocks with one click
  • Toggle Mocks: Enable/disable mocks without leaving the browser

Mock Preview Tab

  • Create/Edit Mocks: Visual interface for creating and editing mocks
  • Response Editor: JSON editor with syntax highlighting
  • Status Code Selection: Choose response status codes
  • Headers Configuration: Add/modify response headers
  • Save to Workspace: Automatically reverse-inject mocks into your workspace

X-Ray Tab

  • Request Analysis: Deep dive into request/response details
  • Timing Information: View request latency and timing breakdown
  • Header Inspection: Inspect all request and response headers
  • Body Analysis: View and analyze request/response bodies

Snapshot Diff Tab

  • Environment Comparison: Compare mock behavior between test and prod
  • Persona Comparison: Compare responses for different personas
  • Reality Level Comparison: Compare behavior at different reality levels
  • Side-by-Side Visualization: See differences highlighted side-by-side

Usage

  1. Open DevTools: Press F12 or right-click → Inspect
  2. Navigate to MockForge Tab: Click “MockForge” in DevTools
  3. Connect to Server: Enter MockForge server URL or use auto-discovery
  4. Capture Requests: Requests are automatically captured
  5. Create Mocks: Click “Mock this endpoint” on any captured request

“Mock this Endpoint” Feature

The “Mock this endpoint” button appears on every captured request:

  1. Click “Mock this endpoint”: Opens the mock preview panel
  2. Review Request Details: See the original request method, path, headers, and body
  3. Edit Response: Modify the response status, headers, and body
  4. Save Mock: Click “Save” to create the mock in your workspace
  5. Auto-Injection: The mock is automatically reverse-injected into your MockForge workspace

Example Workflow:

1. Make API call: GET /api/users/123
2. Request appears in DevTools "Captured Requests" tab
3. Click "Mock this endpoint" button
4. Edit response in preview panel
5. Click "Save" → Mock created in workspace
6. Future requests to /api/users/123 use the mock

Live Response Modification

Modify responses on-the-fly without leaving the browser:

  1. Select a Mock: Click on a mock in the “Mocks” tab
  2. Edit Response: Modify the response JSON directly
  3. Save Changes: Changes are immediately applied
  4. Test: Refresh the page to see the new response

Persona/Scenario Toggling

Switch personas and scenarios directly from DevTools:

  1. Open Mocks Tab: Navigate to the “Mocks” tab
  2. Select Mock: Click on a mock to view details
  3. Change Persona: Use the persona dropdown to switch personas
  4. Change Scenario: Use the scenario dropdown to switch scenarios
  5. Apply: Changes are immediately applied to the mock

Reverse Injection into Workspace

When you create or modify a mock in DevTools, it’s automatically reverse-injected into your MockForge workspace:

  • Automatic Sync: Changes sync to your workspace immediately
  • Workspace Integration: Mocks appear in your workspace configuration
  • Version Control: Mocks can be committed to version control
  • Team Sharing: Other team members see the mocks in shared workspaces

Auto-Mock Generation

When a request fails or returns an error, ForgeConnect can automatically create a mock:

const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  autoMock: true,
  autoMockOnError: true  // Create mock on 4xx/5xx errors
});

Browser SDK

Installation

npm install @mockforge/forgeconnect

Basic Setup

import { ForgeConnect } from '@mockforge/forgeconnect';

const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  autoMock: true,
  interceptFetch: true,
  interceptXHR: true
});

// Start intercepting
forgeConnect.start();

Framework Adapters

React

import { useForgeConnect } from '@mockforge/forgeconnect/react';

function App() {
  const { isConnected, mocks } = useForgeConnect({
    serverUrl: 'http://localhost:3000'
  });

  return (
    <div>
      {isConnected ? 'Connected' : 'Disconnected'}
      <ul>
        {mocks.map(mock => (
          <li key={mock.id}>{mock.path}</li>
        ))}
      </ul>
    </div>
  );
}

Vue

import { useForgeConnect } from '@mockforge/forgeconnect/vue';

export default {
  setup() {
    const { isConnected, mocks } = useForgeConnect({
      serverUrl: 'http://localhost:3000'
    });

    return { isConnected, mocks };
  }
};

Next.js

// pages/_app.tsx
import { ForgeConnectProvider } from '@mockforge/forgeconnect/next';

function MyApp({ Component, pageProps }) {
  return (
    <ForgeConnectProvider serverUrl="http://localhost:3000">
      <Component {...pageProps} />
    </ForgeConnectProvider>
  );
}

Request Interception

ForgeConnect intercepts both fetch and XMLHttpRequest:

const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  interceptFetch: true,
  interceptXHR: true
});

// All fetch requests are intercepted
fetch('/api/users')
  .then(response => response.json())
  .then(data => console.log(data));

// All XHR requests are intercepted
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/users');
xhr.send();

Mock Management

List Mocks

const mocks = await forgeConnect.listMocks();
console.log('Available mocks:', mocks);

Create Mock

const mock = await forgeConnect.createMock({
  method: 'GET',
  path: '/api/users',
  response: {
    status: 200,
    body: { users: [] }
  }
});

Update Mock

await forgeConnect.updateMock(mockId, {
  response: {
    status: 200,
    body: { users: [{ id: 1, name: 'Alice' }] }
  }
});

Delete Mock

await forgeConnect.deleteMock(mockId);

Auth Passthrough

ForgeConnect supports OAuth flows and authentication:

const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  authPassthrough: true,
  authPaths: ['/auth', '/oauth', '/login']
});

Requests to auth paths are passed through to the real server without interception.

Configuration

SDK Configuration

interface ForgeConnectConfig {
  serverUrl: string;
  autoMock?: boolean;
  autoMockOnError?: boolean;
  interceptFetch?: boolean;
  interceptXHR?: boolean;
  authPassthrough?: boolean;
  authPaths?: string[];
  mockPaths?: string[];
  excludePaths?: string[];
}

Extension Configuration

Configure via extension options:

  1. Right-click extension icon
  2. Select “Options”
  3. Configure server URL and settings

Use Cases

Frontend Development

Develop frontend without backend:

// Start ForgeConnect
const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  autoMock: true
});

forgeConnect.start();

// Develop frontend - mocks created automatically

API Testing

Test API integration:

// Capture real API calls
const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  autoMock: false  // Don't auto-create, capture only
});

// Review captured requests
const captures = await forgeConnect.getCaptures();

// Create mocks from captures
for (const capture of captures) {
  await forgeConnect.createMockFromCapture(capture);
}

Debugging

Debug API issues:

// Enable detailed logging
const forgeConnect = new ForgeConnect({
  serverUrl: 'http://localhost:3000',
  debug: true
});

// View intercepted requests in console
forgeConnect.on('request', (request) => {
  console.log('Intercepted:', request);
});

Best Practices

  1. Use Auto-Mock Sparingly: Only enable for development
  2. Filter Requests: Use mockPaths and excludePaths to control interception
  3. Auth Passthrough: Always enable for authentication flows
  4. Version Control Mocks: Export and commit mocks to version control
  5. Test with Real APIs: Periodically test against real APIs

Troubleshooting

Extension Not Connecting

  • Verify MockForge server is running
  • Check server URL is correct
  • Review browser console for errors

Requests Not Intercepted

  • Verify interception is enabled
  • Check request paths match configuration
  • Review SDK logs for errors

Mocks Not Working

  • Verify mock is created correctly
  • Check mock path matches request path
  • Review MockForge server logs

Reality Continuum

Experimental. This feature ships in MockForge but is early: the /__mockforge/continuum/* API and reality_continuum config are live, but traffic blending is currently a per-request mock/upstream split (requires MOCKFORGE_PROXY_UPSTREAM); per-route ratios, time schedules, and field-level blending are not yet applied to live traffic. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

The Reality Continuum feature enables gradual transition from mock to real backend data by intelligently blending responses from both sources. This allows teams to develop and test against a real backend that’s still under construction, smoothly transitioning from 100% mock to 100% real over time.

Overview

The Reality Continuum provides:

  • Dynamic Blending: Intelligently merges mock and real responses based on configurable blend ratios
  • Time-Based Progression: Automatically transitions blend ratios over time using virtual clock
  • Flexible Configuration: Supports per-route, group-level, and global blend ratio settings
  • Multiple Merge Strategies: Field-level merge, weighted selection, or body blending
  • Fallback Handling: Gracefully handles failures from either source

Quick Start

Basic Configuration

reality_continuum:
  enabled: true
  default_ratio: 0.0  # Start with 100% mock
  transition_mode: "manual"  # or "time_based" or "scheduled"
  merge_strategy: "field_level"

Time-Based Progression

Configure automatic progression from mock to real over a time period:

reality_continuum:
  enabled: true
  default_ratio: 0.0
  transition_mode: "time_based"
  time_schedule:
    start_time: "2025-01-01T00:00:00Z"
    end_time: "2025-02-01T00:00:00Z"
    start_ratio: 0.0
    end_ratio: 1.0
    curve: "linear"  # or "exponential" or "sigmoid"

Per-Route Configuration

Set different blend ratios for specific routes:

reality_continuum:
  enabled: true
  default_ratio: 0.0
  routes:
    - pattern: "/api/users/*"
      ratio: 0.5  # 50% real for user endpoints
      enabled: true
    - pattern: "/api/orders/*"
      ratio: 0.3  # 30% real for order endpoints
      group: "api-v1"
      enabled: true

Blend Ratio Priority

The blend ratio is determined in the following order (highest to lowest priority):

  1. Manual Overrides - Set via API calls
  2. Route-Specific Rules - Per-route configuration
  3. Group-Level Overrides - Migration group settings
  4. Time-Based Schedule - If time-based mode is enabled
  5. Default Ratio - Global default setting

Merge Strategies

Field-Level (Default)

Deep merges JSON objects, combines arrays, and uses weighted selection for primitives:

// Mock response
{
  "id": 1,
  "name": "Mock User",
  "email": "[email protected]"
}

// Real response
{
  "id": 2,
  "name": "Real User",
  "status": "active"
}

// Blended (ratio: 0.5)
{
  "id": 1.5,  // Weighted average
  "name": "Real User",  // Selected based on ratio
  "email": "[email protected]",  // From mock (ratio < 0.5)
  "status": "active"  // From real (ratio >= 0.5)
}

Weighted Selection

Randomly selects between mock and real based on ratio (for testing/demo).

Body Blend

Merges arrays, averages numeric fields, and deep merges objects with interleaving.

Transition Curves

Linear

Constant rate of progression:

Ratio
1.0 |                    *
    |               *
    |          *
    |     *
0.0 |*
    +------------------- Time

Exponential

Slow start, fast end:

Ratio
1.0 |                        *
    |                  *
    |            *
    |      *
0.0 |*
    +------------------- Time

Sigmoid

Slow start and end, fast middle:

Ratio
1.0 |                    *
    |               *
    |          *
    |     *
0.0 |*
    +------------------- Time

API Endpoints

Get Blend Ratio

GET /__mockforge/continuum/ratio?path=/api/users/123

Response:

{
  "success": true,
  "data": {
    "path": "/api/users/123",
    "blend_ratio": 0.5,
    "enabled": true,
    "transition_mode": "Manual",
    "merge_strategy": "FieldLevel",
    "default_ratio": 0.0
  }
}

Set Blend Ratio

PUT /__mockforge/continuum/ratio
Content-Type: application/json

{
  "path": "/api/users/*",
  "ratio": 0.75
}

Get Time Schedule

GET /__mockforge/continuum/schedule

Update Time Schedule

PUT /__mockforge/continuum/schedule
Content-Type: application/json

{
  "start_time": "2025-01-01T00:00:00Z",
  "end_time": "2025-02-01T00:00:00Z",
  "start_ratio": 0.0,
  "end_ratio": 1.0,
  "curve": "linear"
}

Manually Advance Ratio

POST /__mockforge/continuum/advance
Content-Type: application/json

{
  "increment": 0.1
}

Enable/Disable

PUT /__mockforge/continuum/enabled
Content-Type: application/json

{
  "enabled": true
}

Integration with Time Travel

The Reality Continuum integrates seamlessly with MockForge’s time travel system. When virtual time is enabled, blend ratios automatically progress based on the virtual clock:

#![allow(unused)]
fn main() {
use mockforge_core::{RealityContinuumEngine, VirtualClock, TimeSchedule};

let clock = Arc::new(VirtualClock::new());
clock.enable_and_set(start_time);

let schedule = TimeSchedule::new(start_time, end_time, 0.0, 1.0);
let config = ContinuumConfig {
    enabled: true,
    transition_mode: TransitionMode::TimeBased,
    time_schedule: Some(schedule),
    ..Default::default()
};

let engine = RealityContinuumEngine::with_virtual_clock(config, clock);
}

Use Cases

Gradual Backend Migration

Start with 100% mock responses and gradually increase real backend usage as endpoints are implemented:

reality_continuum:
  enabled: true
  transition_mode: "time_based"
  time_schedule:
    start_time: "2025-01-01T00:00:00Z"
    end_time: "2025-03-01T00:00:00Z"  # 2 months transition
    start_ratio: 0.0
    end_ratio: 1.0
    curve: "sigmoid"  # Slow start and end

Per-Endpoint Rollout

Different endpoints migrate at different rates:

reality_continuum:
  enabled: true
  routes:
    - pattern: "/api/users/*"
      ratio: 0.9  # Almost fully migrated
    - pattern: "/api/orders/*"
      ratio: 0.3  # Still mostly mock
    - pattern: "/api/payments/*"
      ratio: 0.0  # Not yet migrated

A/B Testing

Compare mock and real responses by blending them:

reality_continuum:
  enabled: true
  default_ratio: 0.5  # 50/50 split
  merge_strategy: "field_level"

Fallback Behavior

When continuum is enabled:

  • Both sources succeed: Responses are blended according to the blend ratio
  • Only proxy succeeds: Real response is returned (fallback to real)
  • Only mock succeeds: Mock response is returned (fallback to mock)
  • Both fail: Error is returned (unless migration mode is Real, which fails hard)

Best Practices

  1. Start Conservative: Begin with default_ratio: 0.0 (100% mock)
  2. Use Time-Based Progression: Automate the transition with time schedules
  3. Monitor Both Sources: Ensure both mock and real backends are healthy
  4. Test Fallback Behavior: Verify graceful degradation when one source fails
  5. Use Groups for Batch Control: Group related routes for coordinated migration
  6. Leverage Virtual Clock: Use time travel to simulate weeks of development in minutes

Limitations

  • Currently supports JSON responses only
  • Merge strategies may not handle all edge cases perfectly
  • Time-based progression requires time travel to be enabled for full effect
  • Blending adds slight latency (both responses must be fetched)

Smart Personas

Experimental. This feature ships in MockForge but is early: persona generation and the /api/v1/consistency/persona* endpoints exist, but the configuration keys and {{persona.*}} template helpers shown below are not all implemented; the current keys are data.persona_domain, persona_consistency_enabled, and persona_registry. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Smart Personas enable generating coherent, consistent mock data using persona profiles with unique backstories and deterministic generation. The same persona always generates the same data, ensuring consistency across endpoints and requests.

Overview

Smart Personas provide:

  • Persona Profiles: Unique personas with IDs and domain associations
  • Coherent Backstories: Template-based backstory generation
  • Persona Relationships: Connections between personas (users, devices, organizations)
  • Deterministic Generation: Same persona = same data every time
  • Domain-Specific Templates: Finance, E-commerce, Healthcare, IoT personas

Quick Start

Enable Smart Personas

# config.yaml
data:
  personas:
    enabled: true
    auto_generate_backstories: true
    domain: "ecommerce"  # or "finance", "healthcare", "iot"

Use in Templates

responses:
  - path: "/api/users/{id}"
    body: |
      {
        "id": "{{persona.id}}",
        "name": "{{persona.name}}",
        "email": "{{persona.email}}",
        "backstory": "{{persona.backstory}}"
      }

Persona Profiles

Automatic Persona Creation

Personas are automatically created when referenced:

# Request to /api/users/123
# Persona with ID "123" is automatically created
# Same persona used for all requests with ID "123"

Manual Persona Creation

#![allow(unused)]
fn main() {
use mockforge_data::{PersonaProfile, PersonaRegistry};

let mut registry = PersonaRegistry::new();
let persona = PersonaProfile::new("user-123", "ecommerce");
registry.add_persona(persona);
}

Backstories

Automatic Backstory Generation

Backstories are automatically generated based on domain:

data:
  personas:
    enabled: true
    auto_generate_backstories: true
    domain: "ecommerce"

Domain-Specific Templates

E-commerce

"Alice is a 32-year-old marketing professional living in San Francisco. 
She frequently shops online for electronics and fashion items. 
Her average order value is $150, and she prefers express shipping."

Finance

"Bob is a 45-year-old investment banker based in New York. 
He manages a portfolio worth $2.5M and prefers conservative investments. 
He has been a customer for 8 years."

Healthcare

"Carol is a 28-year-old nurse practitioner in Boston. 
She manages chronic conditions for 50+ patients. 
She prefers digital health tools and telemedicine."

IoT

"Device-001 is a smart thermostat installed in a 3-bedroom home in Seattle. 
It monitors temperature, humidity, and energy usage. 
It's connected to 5 other smart home devices."

Custom Backstories

Set custom backstories:

#![allow(unused)]
fn main() {
let mut persona = PersonaProfile::new("user-123", "ecommerce");
persona.set_backstory("Custom backstory text".to_string());
}

Persona Relationships

Define Relationships

#![allow(unused)]
fn main() {
use mockforge_data::PersonaRegistry;

let mut registry = PersonaRegistry::new();

// Add relationship
registry.add_relationship(
    "user-123",
    "device-456",
    "owns"
);

// Get related personas
let devices = registry.get_related_personas("user-123", "owns");
}

Relationship Types

Common relationship types:

  • owns - User owns device/organization
  • belongs_to - Device/organization belongs to user
  • manages - User manages organization
  • connected_to - Device connected to other device
  • parent_of - Organization parent-child relationship

Cross-Entity Consistency

Same base ID across different entity types:

#![allow(unused)]
fn main() {
// User persona
let user = registry.get_or_create_persona_by_type("123", EntityType::User, "ecommerce");

// Device persona (same ID, different type)
let device = registry.get_or_create_persona_by_type("123", EntityType::Device, "iot");

// Automatically establishes relationship
}

Deterministic Generation

Same Persona, Same Data

The same persona always generates the same data:

# First request
GET /api/users/123
# Response: {"id": 123, "name": "Alice", "email": "[email protected]"}

# Second request (same persona ID)
GET /api/users/123
# Response: {"id": 123, "name": "Alice", "email": "[email protected]"}  # Same!

Seed-Based Generation

Personas use deterministic seeds:

#![allow(unused)]
fn main() {
let persona = PersonaProfile::new("user-123", "ecommerce");
// Seed is derived from persona ID and domain
// Same ID + same domain = same seed = same data
}

Template Functions

Persona Functions

# In response templates
{
  "id": "{{persona.id}}",
  "name": "{{persona.name}}",
  "email": "{{persona.email}}",
  "phone": "{{persona.phone}}",
  "address": "{{persona.address}}",
  "backstory": "{{persona.backstory}}",
  "traits": "{{persona.traits}}"
}

Relationship Functions

# Get related personas
{
  "user": {
    "id": "{{persona.id}}",
    "name": "{{persona.name}}"
  },
  "devices": "{{persona.related.owns}}"
}

Configuration

Full Configuration

data:
  personas:
    enabled: true
    auto_generate_backstories: true
    domain: "ecommerce"  # finance, healthcare, iot, generic
    backstory_templates:
      ecommerce:
        - "{{name}} is a {{age}}-year-old {{profession}} living in {{city}}."
        - "They frequently shop for {{interests}} with an average order value of ${{avg_order_value}}."
    relationship_types:
      - owns
      - belongs_to
      - manages
      - connected_to

Use Cases

Consistent User Data

Generate consistent user data across endpoints:

# User endpoint
responses:
  - path: "/api/users/{id}"
    body: |
      {
        "id": "{{persona.id}}",
        "name": "{{persona.name}}",
        "email": "{{persona.email}}"
      }

# User's orders endpoint
responses:
  - path: "/api/users/{id}/orders"
    body: |
      {
        "user_id": "{{persona.id}}",
        "user_name": "{{persona.name}}",
        "orders": [...]
      }

Device Relationships

Model device ownership:

# Device endpoint
responses:
  - path: "/api/devices/{id}"
    body: |
      {
        "id": "{{persona.id}}",
        "owner_id": "{{persona.relationship.owner}}",
        "type": "{{persona.type}}"
      }

Organization Hierarchies

Model organizational structures:

# Organization endpoint
responses:
  - path: "/api/organizations/{id}"
    body: |
      {
        "id": "{{persona.id}}",
        "name": "{{persona.name}}",
        "parent_id": "{{persona.relationship.parent}}",
        "children": "{{persona.related.children}}"
      }

Best Practices

  1. Use Consistent IDs: Use the same persona ID across related endpoints
  2. Choose Appropriate Domain: Select domain that matches your use case
  3. Leverage Relationships: Use relationships to model complex data structures
  4. Customize Backstories: Add domain-specific details to backstories
  5. Test Determinism: Verify same persona generates same data

Troubleshooting

Persona Not Found

  • Ensure personas are enabled in configuration
  • Check persona ID is consistent across requests
  • Verify domain matches persona domain

Backstory Not Generated

  • Check auto_generate_backstories is enabled
  • Verify domain is supported
  • Review persona creation logs

Relationships Not Working

  • Verify relationship types are defined
  • Check relationship is added to registry
  • Review relationship query syntax

API Change Forecasting

Experimental. This feature ships in MockForge but is early: the engine and /api/v1/forecasts endpoints exist (they require a Postgres database), and the CLI is mockforge governance forecast generate; the contract_drift config block shown below is not read yet. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Contracts]

API Change Forecasting uses historical sync/diff data to predict likely future contract breaks. This lets teams proactively harden clients before changes occur.

Overview

Instead of reacting to breaking changes, API Change Forecasting analyzes historical patterns to predict:

  • When changes are likely to occur
  • What type of changes (breaking vs non-breaking)
  • Which endpoints are most volatile
  • Seasonal patterns in changes

This is hugely enterprise-friendly—it transforms contract management from reactive to proactive.

Key Features

  • Pattern Analysis: Detects seasonal patterns, volatility, and change frequency
  • Statistical Modeling: Predicts change probability and break probability
  • Multi-Window Forecasting: 30, 90, and 180-day forecasts
  • Hierarchical Aggregation: Workspace, service, and endpoint-level predictions
  • Confidence Scoring: Indicates how reliable each forecast is

How It Works

1. Historical Analysis

The system analyzes historical drift incidents to identify patterns:

  • Change Frequency: How often does this endpoint change?
  • Change Types: What types of changes occur (breaking vs non-breaking)?
  • Seasonal Patterns: Are changes more common at certain times?
  • Volatility Score: How stable is this endpoint?

2. Statistical Modeling

Using the historical data, the system builds statistical models:

  • Change Probability: Likelihood of any change in the forecast window
  • Break Probability: Likelihood of a breaking change
  • Next Change Date: Expected date of next change (if predictable)
  • Confidence: How reliable is this forecast?

3. Forecasting

Forecasts are generated for multiple time windows:

  • 30-day forecast: Short-term predictions
  • 90-day forecast: Medium-term predictions
  • 180-day forecast: Long-term predictions

Usage

CLI Commands

# Generate forecasts for all endpoints
mockforge governance forecast generate

# Forecast for specific service
mockforge governance forecast generate --service-id payments

# Forecast for specific endpoint
mockforge governance forecast generate --endpoint /api/users/{id} --method GET

# Forecast with specific window (30, 90, or 180 days)
mockforge governance forecast generate --window-days 90

API Usage

# Get forecasts
GET /api/v1/forecasts?workspace_id=workspace-123&window_days=90

# Get forecast for specific endpoint (endpoint is a path parameter)
GET /api/v1/forecasts/endpoint/{endpoint}?method=GET&window_days=90

# Get service-level forecast
GET /api/v1/forecasts/service/{service_id}?window_days=90

# Refresh forecasts
POST /api/v1/forecasts/refresh
{
  "workspace_id": "workspace-123",
  "service_id": "payments"
}

Forecast Results

Example Forecast

{
  "endpoint": "/api/users/{id}",
  "method": "GET",
  "forecast_window_days": 90,
  "predicted_change_probability": 0.75,
  "predicted_break_probability": 0.25,
  "next_expected_change_date": "2025-04-15T00:00:00Z",
  "next_expected_break_date": "2025-05-01T00:00:00Z",
  "volatility_score": 0.6,
  "confidence": 0.8,
  "seasonal_patterns": [
    {
      "pattern_type": "monthly",
      "frequency_days": 30.0,
      "last_occurrence": "2025-01-15T00:00:00Z",
      "confidence": 0.7,
      "description": "Changes typically occur monthly"
    }
  ]
}

Understanding Forecasts

  • predicted_change_probability: 0.0-1.0, likelihood of any change
  • predicted_break_probability: 0.0-1.0, likelihood of breaking change
  • volatility_score: 0.0-1.0, how frequently changes occur (higher = more volatile)
  • confidence: 0.0-1.0, how reliable the forecast is
  • seasonal_patterns: Detected patterns in change timing

Real-World Examples

Example 1: Monthly Field Additions

Pattern Detected:

  • This team tends to add fields every 2 weeks
  • Changes are non-breaking (new optional fields)
  • Pattern confidence: 0.8

Forecast:

  • 90-day change probability: 0.9
  • 90-day break probability: 0.1
  • Next expected change: 2 weeks from now

Action: Frontend team can prepare for new optional fields.

Example 2: Quarterly Breaking Changes

Pattern Detected:

  • This service usually breaks its PATCH contract every quarter
  • Changes occur around quarter boundaries
  • Pattern confidence: 0.7

Forecast:

  • 90-day break probability: 0.6
  • Next expected break: End of current quarter

Action: Platform team can schedule client updates before the break.

Example 3: Frequent Refactors

Pattern Detected:

  • This BE team often renames fields during refactors
  • Renames occur every 1-2 months
  • Pattern confidence: 0.6

Forecast:

  • 90-day change probability: 0.8
  • 90-day break probability: 0.5 (renames are breaking)
  • High volatility score: 0.7

Action: Consumer teams should implement field mapping strategies.

Configuration

Enable Forecasting

# mockforge.yaml
contract_drift:
  forecasting:
    enabled: true
    min_incidents_for_forecast: 5  # Need at least 5 incidents
    analysis_windows: [30, 90, 180]  # Days to analyze
    forecast_windows: [30, 90, 180]  # Days to forecast

Forecast Thresholds

contract_drift:
  forecasting:
    enabled: true
    thresholds:
      high_volatility: 0.7  # Volatility score threshold
      high_break_probability: 0.5  # Break probability threshold
      low_confidence: 0.5  # Confidence threshold for warnings

Integration with Drift Budgets

Forecasts integrate with drift budgets:

contract_drift:
  drift_budget:
    max_breaking_changes: 2
    max_non_breaking_changes: 10
  forecasting:
    enabled: true
    # Forecasts help predict if budget will be exceeded

When a forecast predicts budget violations, alerts can be sent proactively.

Webhooks

Forecast updates can trigger webhooks:

webhooks:
  - url: https://slack.com/hooks/...
    events:
      - forecast.prediction_updated
      - forecast.high_volatility_detected
      - forecast.break_probability_high

Best Practices

  1. Collect History: Ensure sufficient historical data (at least 5 incidents)
  2. Review Regularly: Check forecasts weekly/monthly
  3. Act on Predictions: Use forecasts to plan client updates
  4. Track Accuracy: Monitor forecast accuracy over time
  5. Adjust Thresholds: Tune thresholds based on your needs

Troubleshooting

No Forecasts Available

  • Insufficient History: Need at least 5 drift incidents
  • No Patterns: Endpoint may be too stable or too new
  • Low Confidence: Forecasts may be unreliable

Inaccurate Forecasts

  • Pattern Changes: Historical patterns may have changed
  • External Factors: Events outside normal patterns
  • Low Confidence: Check confidence scores

Semantic Drift Notifications

Experimental. This feature ships in MockForge but is early: the /api/v1/semantic-drift/* endpoints exist and the CLI is mockforge governance semantic analyze; there is no CLI for listing or resolving incidents, and the contract_drift config shown below is not read yet. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Contracts]

Semantic Drift Notifications detect when the meaning of an API changes, not just its structure. This is where AI Contract Diff goes from “nice” to “indispensable.”

Overview

Structural diffs catch obvious breaking changes. Semantic drift detection catches subtle changes that break consumers even when the structure appears compatible:

  • Description changes that alter meaning
  • Enum narrowing (values removed)
  • Soft-breaking changes hidden behind oneOf/anyOf
  • Nullable → non-nullable changes
  • Error codes removed

How It Works

Layer 1: Structural Diff

Traditional contract diffing compares:

  • Field types
  • Required vs optional
  • Schema structure
  • HTTP methods

Layer 2: Semantic Analysis

Semantic drift detection adds:

  • LLM-Powered Analysis: Understands meaning, not just structure
  • Rule-Based Detection: Fast detection of common patterns
  • Soft-Breaking Scoring: Quantifies likelihood of breaking consumers
  • Confidence Scoring: Indicates how certain the detection is

Detection Types

Description Changes

Detects when field/endpoint descriptions change meaning:

Before:

{
  "status": {
    "type": "string",
    "description": "Order status: pending, processing, shipped"
  }
}

After:

{
  "status": {
    "type": "string",
    "description": "Order status: pending, processing, shipped, cancelled"
  }
}

Detection: New value added, but description change may indicate behavior change.

Enum Narrowing

Detects when enum values are removed:

Before:

{
  "status": {
    "type": "string",
    "enum": ["pending", "processing", "shipped", "cancelled"]
  }
}

After:

{
  "status": {
    "type": "string",
    "enum": ["pending", "processing", "shipped"]
  }
}

Detection: “cancelled” value removed—breaking change for consumers using it.

Nullable Changes

Detects nullable → non-nullable changes hidden behind oneOf:

Before:

{
  "email": {
    "oneOf": [
      {"type": "string"},
      {"type": "null"}
    ]
  }
}

After:

{
  "email": {
    "type": "string"
  }
}

Detection: Field is no longer nullable—breaking for consumers expecting null.

Error Code Removals

Detects when error codes are removed:

Before:

{
  "responses": {
    "400": {...},
    "404": {...},
    "409": {...}
  }
}

After:

{
  "responses": {
    "400": {...},
    "404": {...}
  }
}

Detection: 409 error code removed—breaking for consumers handling conflicts.

Soft-Breaking Changes

Detects changes that may break consumers but aren’t structurally breaking:

  • Format changes: Email format validation tightened
  • Constraint changes: Min/max values changed
  • Pattern changes: Regex pattern modified
  • Example changes: Examples suggest different behavior

Usage

CLI Commands

# Analyze semantic drift for an endpoint between two contract versions
mockforge governance semantic analyze --before old.yaml --after new.yaml --endpoint /api/users/{id} --method GET

# Write the result to a file
mockforge governance semantic analyze --before old.yaml --after new.yaml --endpoint /api/users/{id} --method GET --output drift.json

Listing incidents is only available over the API; there is no CLI command for listing or resolving incidents.

API Usage

# Analyze semantic drift
POST /api/v1/semantic-drift/analyze
{
  "before_spec": "...",
  "after_spec": "...",
  "endpoint": "/api/users/{id}",
  "method": "GET"
}

# Get incidents
GET /api/v1/semantic-drift/incidents?workspace_id=workspace-123

# Get incident details
GET /api/v1/semantic-drift/incidents/{id}

Semantic Drift Results

Example Result

{
  "semantic_confidence": 0.85,
  "soft_breaking_score": 0.7,
  "change_type": "enum_narrowing",
  "semantic_mismatches": [
    {
      "type": "SemanticEnumNarrowing",
      "severity": "high",
      "location": "/api/orders/{id}",
      "field": "status",
      "description": "Enum value 'cancelled' removed",
      "before": ["pending", "processing", "shipped", "cancelled"],
      "after": ["pending", "processing", "shipped"],
      "confidence": 0.9
    }
  ],
  "llm_analysis": {
    "reasoning": "Removing 'cancelled' status breaks consumers that rely on this value for order cancellation flows.",
    "impact": "High - affects order cancellation workflows",
    "recommendation": "Deprecate 'cancelled' first, then remove in next major version"
  }
}

Understanding Scores

  • semantic_confidence: 0.0-1.0, how certain the semantic analysis is
  • soft_breaking_score: 0.0-1.0, likelihood this breaks consumers
  • change_type: Type of semantic change detected
  • confidence: Individual mismatch confidence

Configuration

Enable Semantic Drift Detection

# mockforge.yaml
contract_drift:
  semantic_drift:
    enabled: true
    confidence_threshold: 0.65  # Minimum confidence to report
    use_llm_analysis: true  # Enable LLM-powered analysis
    rule_based_detection: true  # Enable rule-based detection

LLM Configuration

contract_drift:
  semantic_drift:
    enabled: true
    llm:
      provider: openai  # or anthropic, local
      model: gpt-4
      temperature: 0.3  # Lower = more deterministic

Integration with Drift Budgets

Semantic drift incidents integrate with drift budgets:

contract_drift:
  drift_budget:
    max_breaking_changes: 2
    semantic_drift:
      enabled: true
      # Semantic drift incidents count toward budget

Webhooks

Semantic drift detection can trigger webhooks:

webhooks:
  - url: https://slack.com/hooks/...
    events:
      - semantic_drift.detected
      - semantic_drift.high_confidence
      - semantic_drift.soft_breaking

Best Practices

  1. Enable LLM Analysis: More accurate than rule-based alone
  2. Review High Confidence: Focus on high-confidence detections first
  3. Track Soft-Breaking: Monitor soft-breaking scores
  4. Document Changes: Explain why semantic changes were made
  5. Deprecate First: Use deprecation before removing features

Real-World Examples

Example 1: Description Change

Change:

  • Before: “User email address”
  • After: “User email address (must be verified)”

Detection: Semantic change—implies new validation requirement.

Impact: Consumers may need to handle verification errors.

Example 2: Enum Narrowing

Change:

  • Before: ["active", "inactive", "suspended"]
  • After: ["active", "inactive"]

Detection: “suspended” removed—breaking for consumers using it.

Impact: High—consumers relying on “suspended” will break.

Example 3: Soft-Breaking Format Change

Change:

  • Before: Email format: any string
  • After: Email format: must match RFC 5322

Detection: Soft-breaking—may break consumers with invalid emails.

Impact: Medium—only affects consumers with invalid data.

Troubleshooting

False Positives

  • Low Confidence: Check confidence scores
  • Context Missing: LLM may need more context
  • Tuning Needed: Adjust confidence thresholds

Missed Detections

  • Enable LLM: Rule-based may miss subtle changes
  • Lower Threshold: May be filtering valid detections
  • Review Manually: Some changes need human review

Contract Threat Modeling

Experimental. This feature ships in MockForge but is early: the /api/v1/threats/* endpoints exist (assessment is POST /api/v1/threats/assess) and the CLI is mockforge governance threat assess. Listing assessments and remediations is only available over the API (findings and remediations are read from the database and return empty lists without one). Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Contracts]

Contract Threat Modeling is a new category: contract security posture. MockForge becomes not only a contract tool, but an API safety platform.

Overview

Beyond structural validation, Contract Threat Modeling analyzes APIs for security risks:

  • PII Exposure: APIs returning too much personally identifiable information
  • DoS Risk: Unbounded arrays and missing pagination
  • Error Leakage: Stack traces and internal details in error responses
  • Schema Design Issues: Excessive optional fields, inconsistent patterns

Threat Categories

PII Exposure

Detects when APIs return sensitive personal information:

Example:

{
  "user": {
    "id": "123",
    "email": "[email protected]",
    "ssn": "123-45-6789",  // ⚠️ PII exposure
    "credit_card": "****-****-****-1234"  // ⚠️ PII exposure
  }
}

Detection: Fields like ssn, credit_card, passport_number are flagged.

Remediation: Mask or remove PII from responses.

DoS Risk (Unbounded Arrays)

Detects arrays without size limits:

Example:

{
  "users": {
    "type": "array",
    "items": {...}
    // ⚠️ No maxItems constraint
  }
}

Risk: Attackers can request unbounded arrays, causing DoS.

Remediation: Add maxItems constraint:

{
  "users": {
    "type": "array",
    "items": {...},
    "maxItems": 100  // ✅ Bounded
  }
}

Error Leakage

Detects stack traces and internal details in error responses:

Example:

{
  "error": {
    "message": "Internal server error",
    "stack_trace": "at com.example.Service.handle()...",  // ⚠️ Leakage
    "internal_id": "uuid-123",  // ⚠️ Internal details
    "database_query": "SELECT * FROM users..."  // ⚠️ SQL leak
  }
}

Risk: Exposes internal implementation details.

Remediation: Sanitize error messages:

{
  "error": {
    "message": "An error occurred",
    "code": "ERROR_CODE"  // ✅ Sanitized
  }
}

Schema Design Issues

Detects problematic schema patterns:

Excessive Optional Fields:

{
  "user": {
    "id": "required",
    "name": "optional",  // ⚠️ Too many optional fields
    "email": "optional",
    "phone": "optional",
    "address": "optional",
    // ... 20 more optional fields
  }
}

Risk: Inconsistent responses, unclear contracts.

Remediation: Split into separate schemas or make more fields required.

Usage

CLI Commands

# Assess a contract for threats
mockforge governance threat assess --spec api.yaml

# Scope the assessment to a workspace/service
mockforge governance threat assess --spec api.yaml --workspace-id workspace-123 --service-id payments

# Assess a specific endpoint and write the result to a file
mockforge governance threat assess --spec api.yaml --endpoint /api/users/{id} --method GET --output threats.json

API Usage

# Assess a contract (spec is the OpenAPI document as a YAML/JSON string)
POST /api/v1/threats/assess
{
  "spec": "...",
  "workspace_id": "workspace-123",
  "service_name": "payments"
}

# Get assessments for a workspace, service, or endpoint
GET /api/v1/threats/workspace/{workspace_id}
GET /api/v1/threats/service/{service_id}
GET /api/v1/threats/endpoint/{endpoint}

# List findings
GET /api/v1/threats/findings

# Get remediation suggestions
GET /api/v1/threats/remediations

Threat Assessment Results

Example Assessment

{
  "workspace_id": "workspace-123",
  "service_name": "payments",
  "endpoint": "/api/payments",
  "threat_level": "high",
  "threat_score": 0.75,
  "threat_categories": ["pii_exposure", "dos_risk"],
  "findings": [
    {
      "finding_type": "PiiExposure",
      "severity": "high",
      "field_path": "body.card_number",
      "description": "Credit card number exposed in response",
      "confidence": 0.9
    },
    {
      "finding_type": "UnboundedArrays",
      "severity": "high",
      "field_path": "body.transactions",
      "description": "Transactions array has no maxItems constraint",
      "confidence": 1.0
    }
  ],
  "remediation_suggestions": [
    {
      "finding_id": "finding_body.card_number",
      "suggestion": "Mask or remove card_number from response",
      "code_example": {
        "before": "\"card_number\": \"1234-5678-9012-3456\"",
        "after": "\"card_number\": \"****-****-****-3456\""
      },
      "confidence": 0.8,
      "priority": "high"
    }
  ]
}

Threat Levels

  • Low: Minor issues, acceptable risks
  • Medium: Issues that should be addressed
  • High: Significant security risks
  • Critical: Immediate security concerns

Threat Score

0.0-1.0 score indicating overall threat level:

  • 0.0-0.3: Low risk
  • 0.3-0.6: Medium risk
  • 0.6-0.8: High risk
  • 0.8-1.0: Critical risk

AI-Powered Remediation

MockForge provides AI-generated remediation suggestions:

Example Remediation

Finding: Unbounded array detected

Remediation:

{
  "suggestion": "Add maxItems constraint to array schema",
  "code_example": {
    "type": "array",
    "items": {...},
    "maxItems": 100
  },
  "confidence": 0.9,
  "priority": "high"
}

Configuration

Enable Threat Modeling

# mockforge.yaml
contract_drift:
  threat_modeling:
    enabled: true
    pii_detection: true
    dos_analysis: true
    error_analysis: true
    schema_analysis: true
    ai_remediation: true  # Enable AI-powered suggestions

Thresholds

contract_drift:
  threat_modeling:
    enabled: true
    thresholds:
      high_threat_score: 0.7
      critical_threat_score: 0.9
      max_array_size: 1000  # Default maxItems recommendation

Integration with Drift Budgets

Threat assessments can trigger drift budget violations:

contract_drift:
  drift_budget:
    max_breaking_changes: 2
    threat_modeling:
      enabled: true
      # High-threat findings count toward budget

Webhooks

Threat assessments can trigger webhooks:

webhooks:
  - url: https://slack.com/hooks/...
    events:
      - threat_assessment.completed
      - threat_remediation.suggested
      - threat_critical_detected

Real-World Examples

Example 1: PII Exposure

Finding:

{
  "user": {
    "ssn": "123-45-6789"  // ⚠️ PII
  }
}

Remediation:

  • Remove SSN from response
  • Or mask: "ssn": "***-**-6789"
  • Or return only last 4: "ssn_last4": "6789"

Example 2: DoS Risk

Finding:

{
  "products": {
    "type": "array",
    "items": {...}
    // No maxItems
  }
}

Remediation:

{
  "products": {
    "type": "array",
    "items": {...},
    "maxItems": 100  // ✅ Bounded
  }
}

Example 3: Error Leakage

Finding:

{
  "error": {
    "stack_trace": "at com.example..."  // ⚠️ Leakage
  }
}

Remediation:

{
  "error": {
    "message": "An error occurred",
    "code": "INTERNAL_ERROR"  // ✅ Sanitized
  }
}

Best Practices

  1. Run Regularly: Assess contracts in CI/CD pipeline
  2. Fix High Priority: Address high/critical findings immediately
  3. Review AI Suggestions: AI suggestions are helpful but review manually
  4. Document Exceptions: Document why certain risks are acceptable
  5. Track Over Time: Monitor threat scores over time

Troubleshooting

False Positives

  • Field Names: Some field names may trigger false PII detection
  • Context Missing: AI may need more context
  • Tuning Needed: Adjust detection thresholds

Missed Threats

  • Enable All Analyzers: Ensure all analyzers are enabled
  • Review Manually: Some threats need human review
  • Update Patterns: Keep PII patterns updated

Snapshot Diff Between Environments

Experimental. This feature ships in MockForge but is early: the comparison API is served at /__mockforge/api/snapshot-diff/snapshots/compare with in-memory storage; there is no mockforge snapshot diff command yet, and environment/persona/reality comparisons do not yet capture distinct states. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [DevX]

Snapshot Diff provides side-by-side visualization for comparing mock behavior between different environments, personas, scenarios, or “realities” (Reality 0.1 vs Reality 0.9). This is amazing for demos and debugging.

Overview

Snapshot Diff enables you to:

  • Compare Test vs Prod mock behavior
  • Compare Persona A vs Persona B responses
  • Compare Reality 0.1 vs Reality 0.9 behavior
  • Compare Scenarios side-by-side
  • Visualize Differences with highlighted changes

Usage

Browser Extension

  1. Open DevTools
  2. Navigate to “MockForge” tab
  3. Select “Snapshot Diff” panel
  4. Choose comparison type
  5. View side-by-side diff

API Usage

# Compare snapshots (management API on the HTTP server)
POST /__mockforge/api/snapshot-diff/snapshots/compare
{
  "left_environment_id": "test",
  "right_environment_id": "prod"
}

# Capture and list snapshots
POST /__mockforge/api/snapshot-diff/snapshots
GET  /__mockforge/api/snapshot-diff/snapshots
GET  /__mockforge/api/snapshot-diff/snapshots/{id}

The compare request also accepts left_snapshot_id/right_snapshot_id, left_persona_id/right_persona_id, left_scenario_id/right_scenario_id, and left_reality_level/right_reality_level.

CLI Usage

There is no mockforge snapshot diff command yet. The mockforge snapshot command manages time-travel state snapshots (save, load, list, info, delete, validate) and does not compare them; use the API above instead.

Comparison Types

Environment Comparison

Compare mock behavior between environments:

Test Environment              Prod Environment
─────────────────            ─────────────────
GET /api/users/123           GET /api/users/123
Status: 200                  Status: 200
Body: {...}                  Body: {...}
  id: "123"                    id: "123"
  name: "Test User"             name: "Prod User"  ⚠️
  email: "test@..."             email: "prod@..."  ⚠️

Persona Comparison

Compare responses for different personas:

Premium Customer              Regular Customer
─────────────────            ─────────────────
GET /api/users/123           GET /api/users/123
Status: 200                  Status: 200
Body: {...}                  Body: {...}
  tier: "premium"              tier: "regular"  ⚠️
  features: [...]               features: [...]  ⚠️

Reality Level Comparison

Compare behavior at different reality levels:

Reality 0.1 (Low)            Reality 0.9 (High)
─────────────────            ─────────────────
GET /api/users/123           GET /api/users/123
Status: 200                  Status: 200
Body: {...}                  Body: {...}
  # Synthetic data             # Blended with real
  id: "generated-123"          id: "real-user-123"  ⚠️
  name: "Generated Name"        name: "Real Name"  ⚠️

Scenario Comparison

Compare different scenarios:

Happy Path                   Error Path
─────────────────            ─────────────────
POST /api/orders             POST /api/orders
Status: 201                  Status: 400
Body: {...}                  Body: {...}
  status: "created"            error: "Invalid..."  ⚠️

Diff Visualization

Side-by-Side View

Left Snapshot                Right Snapshot
─────────────────            ─────────────────
Status: 200                  Status: 200
Headers:                     Headers:
  Content-Type: json            Content-Type: json
Body:                         Body:
  {                             {
    "id": "123",                "id": "123",
    "name": "User A",           "name": "User B",  ⚠️
    "email": "a@..."            "email": "b@..."   ⚠️
  }                             }

Difference Types

  • Missing in Right: Fields present in left but not right
  • Missing in Left: Fields present in right but not left
  • Status Code Mismatch: Different status codes
  • Body Mismatch: Different response bodies
  • Headers Mismatch: Different headers

Use Cases

Demo Preparation

Compare scenarios to prepare demos:

# Compare demo scenarios
POST /__mockforge/api/snapshot-diff/snapshots/compare
{
  "left_scenario_id": "demo-basic",
  "right_scenario_id": "demo-premium"
}

Debugging

Compare behavior to debug issues:

# Compare test vs prod to find differences
POST /__mockforge/api/snapshot-diff/snapshots/compare
{
  "left_environment_id": "test",
  "right_environment_id": "prod"
}

Reality Progression

Compare reality levels to understand progression:

# Compare low vs high reality
POST /__mockforge/api/snapshot-diff/snapshots/compare
{
  "left_reality_level": 0.1,
  "right_reality_level": 0.9
}

Configuration

Snapshot Storage

# mockforge.yaml
snapshots:
  enabled: true
  storage:
    type: database  # or file
    retention_days: 30

Comparison Options

snapshots:
  comparison:
    include_headers: true
    include_timing: true
    diff_format: unified  # or side-by-side

Best Practices

  1. Take Snapshots Regularly: Capture snapshots at key points
  2. Compare Before Deploy: Compare test vs prod before deployment
  3. Document Differences: Document expected differences
  4. Use for Demos: Use comparisons in demos and presentations
  5. Track Over Time: Compare snapshots over time to track changes

Deceptive Deploys

Experimental. This feature ships in MockForge but is early: mockforge deploy and the deceptive_deploy config apply production-like headers, CORS, rate limiting, and OAuth settings, and can start a tunnel, but the mock only resembles production as closely as your spec, fixtures, and config make it. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

Deceptive Deploy allows you to deploy mock APIs that look identical to production endpoints. Perfect for front-end demos, PoCs, investor prototypes, and client presentations without exposing production systems.

Overview

Deceptive Deploy configures MockForge to automatically:

  • ✅ Add production-like headers to all responses
  • ✅ Configure CORS to match production settings
  • ✅ Apply production-like rate limiting
  • ✅ Support OAuth flows identical to production
  • ✅ Deploy to public URLs via tunneling

The result: mock APIs that behave like your production endpoints at the HTTP level (headers, CORS, rate limits, auth), so front-end code runs against them unchanged.

Quick Start

Basic Deployment

# Deploy with production preset
mockforge deploy deploy --production-preset --spec api.yaml

# Deploy with custom config
mockforge deploy deploy --config config.yaml --spec api.yaml

Configuration File

Create a config.yaml file:

http:
  port: 3000
  openapi_spec: "./api-spec.yaml"

deceptive_deploy:
  enabled: true
  auto_tunnel: true

Start the Server

mockforge serve --config config.yaml

The server will automatically:

  • Apply production-like headers
  • Configure CORS
  • Set up rate limiting
  • Start a tunnel (if auto_tunnel: true)

Configuration

Basic Configuration

deceptive_deploy:
  enabled: true
  auto_tunnel: true

Full Configuration

deceptive_deploy:
  enabled: true

  # Production-like CORS
  cors:
    allowed_origins: ["*"]
    allowed_methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
    allowed_headers: ["*"]
    allow_credentials: true

  # Production-like rate limiting
  rate_limit:
    requests_per_minute: 1000
    burst: 2000
    per_ip: true

  # Production headers (supports templates)
  headers:
    X-API-Version: "1.0"
    X-Request-ID: "{{uuid}}"
    X-Powered-By: "MockForge"

  # OAuth configuration (optional)
  oauth:
    client_id: "your-client-id"
    client_secret: "your-client-secret"
    introspection_url: "https://auth.example.com/introspect"

  # Custom domain (optional)
  custom_domain: "api.example.com"

  # Auto-start tunnel
  auto_tunnel: true

Production Headers

Deceptive Deploy automatically adds configured headers to all responses. Headers support template expansion:

Supported Templates

  • {{uuid}} - Generates a unique UUID v4 for each request
  • {{now}} - Current timestamp in RFC3339 format
  • {{timestamp}} - Current Unix timestamp (seconds)

Example

headers:
  X-Request-ID: "{{uuid}}"           # Unique ID per request
  X-Timestamp: "{{timestamp}}"      # Unix timestamp
  X-Request-Time: "{{now}}"         # RFC3339 timestamp
  X-API-Version: "1.0"               # Static value

Common Production Headers

headers:
  # Request tracking
  X-Request-ID: "{{uuid}}"
  X-Correlation-ID: "{{uuid}}"

  # API information
  X-API-Version: "1.0"
  X-Environment: "production"

  # Server information
  X-Powered-By: "MockForge"
  Server: "MockForge/1.0"

  # Custom headers
  X-Rate-Limit-Remaining: "999"
  X-Rate-Limit-Reset: "{{timestamp}}"

CORS Configuration

Deceptive Deploy can configure CORS to match production settings:

cors:
  # Allow all origins (use specific origins in production)
  allowed_origins:
    - "*"
    # Or specific origins:
    # - "https://app.example.com"
    # - "https://staging.example.com"

  # Allowed HTTP methods
  allowed_methods:
    - "GET"
    - "POST"
    - "PUT"
    - "DELETE"
    - "PATCH"
    - "OPTIONS"

  # Allowed headers
  allowed_headers:
    - "*"
    # Or specific headers:
    # - "Content-Type"
    # - "Authorization"
    # - "X-API-Key"

  # Allow credentials (cookies, authorization headers)
  allow_credentials: true

Rate Limiting

Configure production-like rate limiting:

rate_limit:
  # Requests per minute
  requests_per_minute: 1000

  # Burst capacity (maximum requests in a short burst)
  burst: 2000

  # Enable per-IP rate limiting
  per_ip: true

Rate Limit Headers

When rate limiting is enabled, responses include rate limit headers:

  • X-Rate-Limit-Limit: Maximum requests per minute
  • X-Rate-Limit-Remaining: Remaining requests in current window
  • X-Rate-Limit-Reset: Unix timestamp when limit resets

OAuth Configuration

Configure OAuth flows to match production:

oauth:
  client_id: "your-client-id"
  client_secret: "your-client-secret"
  introspection_url: "https://auth.example.com/introspect"
  auth_url: "https://auth.example.com/authorize"
  token_url: "https://auth.example.com/token"
  token_type_hint: "access_token"

This enables:

  • Token introspection
  • Authorization code flow
  • Client credentials flow
  • Token validation

Tunneling

Deceptive Deploy can automatically start a tunnel to expose your mock API via a public URL:

deceptive_deploy:
  auto_tunnel: true
  custom_domain: "api.example.com"  # Optional

Tunnel Providers

  • Self-hosted: Use your own tunnel server
  • Cloud: Use MockForge Cloud (if available)
  • Cloudflare: Use Cloudflare Tunnel (coming soon)

Manual Tunnel

# Start tunnel manually
mockforge tunnel start \
  --local-url http://localhost:3000 \
  --subdomain my-api

CLI Commands

Deploy

# Deploy with production preset
mockforge deploy deploy --production-preset --spec api.yaml

# Deploy with custom config
mockforge deploy deploy --config config.yaml --spec api.yaml

# Deploy with auto-tunnel
mockforge deploy deploy --config config.yaml --auto-tunnel

# Deploy with custom domain
mockforge deploy deploy --config config.yaml --custom-domain api.example.com

Status

# Get deployment status
mockforge deploy status --config config.yaml

Stop

# Stop deployment
mockforge deploy stop --config config.yaml

Use Cases

Front-End Demo

# config.yaml
http:
  port: 3000
  openapi_spec: "./api.yaml"

deceptive_deploy:
  enabled: true
  auto_tunnel: true
  headers:
    X-API-Version: "1.0"
    X-Request-ID: "{{uuid}}"
# Deploy
mockforge deploy deploy --config config.yaml

# Start server
mockforge serve --config config.yaml

# Front-end connects to public URL
# https://abc123.tunnel.mockforge.dev

Investor Prototype

deceptive_deploy:
  enabled: true
  cors:
    allowed_origins: ["*"]
    allow_credentials: true
  rate_limit:
    requests_per_minute: 1000
    burst: 2000
  headers:
    X-API-Version: "1.0"
    X-Environment: "production"
  auto_tunnel: true
  custom_domain: "api.demo.example.com"

PoC with OAuth

deceptive_deploy:
  enabled: true
  oauth:
    client_id: "demo-client"
    client_secret: "demo-secret"
    introspection_url: "https://auth.example.com/introspect"
  headers:
    X-Request-ID: "{{uuid}}"
    X-Auth-Provider: "OAuth2"

Best Practices

1. Use Specific Origins

Instead of *, use specific origins:

cors:
  allowed_origins:
    - "https://app.example.com"
    - "https://staging.example.com"

2. Set Realistic Rate Limits

Match production rate limits:

rate_limit:
  requests_per_minute: 1000  # Match production
  burst: 2000

3. Use Meaningful Headers

Add headers that match production:

headers:
  X-API-Version: "1.0"
  X-Request-ID: "{{uuid}}"
  X-Environment: "production"

4. Secure OAuth Credentials

Never commit OAuth secrets to version control:

oauth:
  client_id: "${OAUTH_CLIENT_ID}"
  client_secret: "${OAUTH_CLIENT_SECRET}"

5. Use Custom Domains

For professional presentations:

deceptive_deploy:
  custom_domain: "api.example.com"

Troubleshooting

Headers Not Appearing

Check that deceptive deploy is enabled:

deceptive_deploy:
  enabled: true
  headers:
    X-Request-ID: "{{uuid}}"

CORS Errors

Verify CORS configuration:

cors:
  allowed_origins: ["*"]  # Or specific origins
  allow_credentials: true

Rate Limiting Too Strict

Adjust rate limits:

rate_limit:
  requests_per_minute: 1000  # Increase if needed
  burst: 2000

Tunnel Not Starting

Check tunnel configuration:

deceptive_deploy:
  auto_tunnel: true

Or start manually:

mockforge tunnel start --local-url http://localhost:3000

Voice + LLM Interface

Experimental. This feature ships in MockForge but is early. It needs an LLM provider (Ollama, OpenAI, or Anthropic) to interpret commands. Voice input in the admin UI uses the browser’s speech recognition, so it only works in browsers that support it (for example Chrome and Edge). The CLI does not capture from a microphone: it takes typed commands, or a path to an audio file when the CLI is built with the stt-cloud feature and an OpenAI Whisper or Google Speech key is set. Behavior, commands, and configuration may change between releases. Report issues at https://github.com/SaaSy-Solutions/mockforge/issues.

The Voice + LLM Interface allows you to create mock APIs conversationally using natural language commands, powered by LLM interpretation. Generate OpenAPI specifications and mock APIs from voice or text commands.

Overview

The Voice + LLM Interface provides:

  • Voice Command Parsing: Use natural language to describe APIs
  • OpenAPI Generation: Automatically generate OpenAPI 3.0 specifications
  • Conversational Mode: Multi-turn interactions for complex APIs
  • Single-Shot Mode: Complete API generation in one command
  • CLI and Web UI: Use from command line or web interface

Quick Start

CLI Usage

Single-Shot Mode

Create a complete API in one command:

# Create API from text command
mockforge voice create \
  --command "Create a user management API with endpoints for listing users, getting a user by ID, creating users, and updating users" \
  --output api.yaml

# Or use interactive input
mockforge voice create
# Enter your command when prompted

Conversational Mode

Build APIs through conversation:

# Start interactive conversation
mockforge voice interactive

# Example conversation:
# > Create a user management API
# > Add an endpoint to get user by email
# > Add authentication to all endpoints
# > Show me the spec
# > done

Web UI Usage

  1. Navigate to Voice page in Admin UI
  2. Click microphone or type your command
  3. View generated OpenAPI spec
  4. Download or use the spec

Features

Natural Language Commands

Describe your API in plain English:

Create a REST API for an e-commerce store with:
- Product catalog with categories
- Shopping cart management
- Order processing
- User authentication

OpenAPI Generation

Automatically generates complete OpenAPI 3.0 specifications:

openapi: 3.0.0
info:
  title: E-commerce Store API
  version: 1.0.0
paths:
  /products:
    get:
      summary: List products
      responses:
        '200':
          description: List of products
  /cart:
    post:
      summary: Add item to cart
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                product_id:
                  type: integer
                quantity:
                  type: integer

Conversational Mode

Build complex APIs through multiple interactions:

> Create a blog API
✓ Created blog API with posts endpoint

> Add comments to posts
✓ Added comments endpoint with post_id relationship

> Add user authentication
✓ Added authentication to all endpoints

> Show me the spec
[Displays generated OpenAPI spec]

> done
✓ Saved to blog-api.yaml

Single-Shot Mode

Generate complete APIs in one command:

mockforge voice create \
  --command "Create a task management API with CRUD operations for tasks, projects, and users" \
  --output task-api.yaml

CLI Commands

Create (Single-Shot)

mockforge voice create \
  --command "<description>" \
  --output <file> \
  --serve --port 3000

Options:

  • -c, --command: Natural language description of API (prompts or reads stdin if omitted)
  • -o, --output: Output file path. The format follows the extension (.yaml/.yml for YAML, otherwise JSON). If omitted, the spec is not saved.
  • --serve: Start a mock server with the generated spec
  • --port: HTTP port used with --serve (default: 3000)

There are no per-command provider or model flags; the LLM provider is configured as described in AI Provider Configuration.

Interactive (Conversational)

mockforge voice interactive --output api.yaml

Options: -o, --output, --serve, and --port (same meaning as for create).

Special Commands:

  • help - Show available commands
  • show spec - Display current OpenAPI spec
  • save <file> - Save spec to file
  • done - Exit and save
  • exit - Exit without saving

Web UI

Voice Input

Use Web Speech API for voice input:

  1. Click microphone button
  2. Speak your command
  3. View real-time transcript
  4. See generated spec

Text Input

Type commands directly:

  1. Enter command in text field
  2. Click “Generate” or press Enter
  3. View generated spec
  4. Download or use spec

Command History

View last 10 commands:

  • Click on history item to reuse
  • Edit before regenerating
  • Save successful commands

Configuration

AI Provider Configuration

voice:
  enabled: true
  ai_provider: "ollama"  # or "openai", "anthropic"
  ai_model: "llama3.2"
  ai_base_url: "http://localhost:11434"  # For Ollama
  ai_api_key: "${AI_API_KEY}"  # For OpenAI/Anthropic

CLI Configuration

The voice + LLM interface uses the shared RAG/LLM env vars rather than dedicated MOCKFORGE_VOICE_* vars:

# Use Ollama (free, local)
export MOCKFORGE_RAG_PROVIDER=ollama
export MOCKFORGE_RAG_MODEL=llama3
export MOCKFORGE_RAG_API_ENDPOINT=http://localhost:11434

# Or OpenAI
export MOCKFORGE_RAG_PROVIDER=openai
export MOCKFORGE_RAG_MODEL=gpt-3.5-turbo
export MOCKFORGE_RAG_API_KEY=sk-...

Voice-specific YAML knobs (voice.ai_provider, etc.) override the shared env vars when both are set.

API Endpoints

Process Voice Command

POST /api/v2/voice/process
Content-Type: application/json

{
  "command": "Create a user management API",
  "mode": "single_shot",  # or "conversational"
  "conversation_id": null  # For conversational mode
}

Response:

{
  "success": true,
  "spec": {
    "openapi": "3.0.0",
    "info": {...},
    "paths": {...}
  },
  "conversation_id": "uuid"  # For conversational mode
}

Continue Conversation

POST /api/v2/voice/process
Content-Type: application/json

{
  "command": "Add authentication",
  "mode": "conversational",
  "conversation_id": "uuid"
}

Use Cases

Rapid Prototyping

Quickly create API prototypes:

mockforge voice create \
  --command "Create a simple todo API with CRUD operations" \
  --output todo-api.yaml

API Design

Design APIs by describing them:

mockforge voice interactive

# > Create a social media API
# > Add posts, comments, and likes
# > Add user profiles
# > Show me the spec

Learning

Learn OpenAPI by example:

# Generate spec
mockforge voice create --command "..."

# Review generated spec
cat generated-api.yaml

Best Practices

  1. Be Specific: Provide clear, detailed descriptions
  2. Iterate: Use conversational mode for complex APIs
  3. Review Generated Specs: Always review and validate generated specs
  4. Use Local LLMs: Use Ollama for faster, free generation
  5. Save Good Examples: Save successful commands for reuse

Troubleshooting

Command Not Understood

  • Be more specific in your description
  • Break complex APIs into smaller parts
  • Use conversational mode for clarification

Spec Generation Fails

  • Check AI provider is accessible
  • Verify API key is set (for OpenAI/Anthropic)
  • Review server logs for errors

Voice Input Not Working

  • Check browser permissions for microphone
  • Verify Web Speech API is supported
  • Use text input as fallback

Generative Schema Mode

Planned / not yet available. The generative-schema library exists in mockforge-core, but it is not exposed yet: there is no CLI for it (mockforge generate only accepts an OpenAPI --spec), and no preview, edit, or VBR-integration commands. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Generative Schema Mode enables you to generate complete API ecosystems from JSON payloads. Simply provide example JSON data, and MockForge automatically creates routes, schemas, and entity relationships for a fully functional mock API.

Overview

Generative Schema Mode transforms example JSON payloads into:

  • Complete OpenAPI specifications with all endpoints
  • Automatic CRUD routes for each entity
  • Entity relationship inference from data structure
  • One-click environment creation ready for deployment
  • Preview and edit generated schemas before deployment

Quick Start

Generate from JSON

There is no CLI for generating an OpenAPI ecosystem from JSON payloads yet. mockforge generate only generates from an OpenAPI spec (--spec), and does not accept JSON payload files, inline JSON, or a --serve option.

Serving JSON Data Today

To get CRUD routes from a JSON file right now, use quick mode. It serves the data directly (it does not produce an OpenAPI spec or infer relationships):

# Serve CRUD routes for every root-level key in data.json
mockforge quick data.json --port 3000

How It Works

1. Entity Inference

MockForge analyzes JSON payloads to infer entity structures:

Input JSON:

{
  "users": [
    {"id": 1, "name": "Alice", "email": "[email protected]"},
    {"id": 2, "name": "Bob", "email": "[email protected]"}
  ],
  "posts": [
    {"id": 1, "user_id": 1, "title": "First Post", "content": "..."},
    {"id": 2, "user_id": 1, "title": "Second Post", "content": "..."}
  ]
}

Inferred Entities:

  • User entity with fields: id, name, email
  • Post entity with fields: id, user_id, title, content
  • Relationship: User has many Post (via user_id)

2. Route Generation

Automatically generates CRUD routes for each entity:

Generated Routes:

  • GET /users - List all users
  • GET /users/{id} - Get user by ID
  • POST /users - Create user
  • PUT /users/{id} - Update user
  • DELETE /users/{id} - Delete user

Same routes generated for posts.

3. Schema Building

Creates complete OpenAPI 3.0 specification:

openapi: 3.0.0
info:
  title: Generated API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email

Configuration

Generation Options

generative_schema:
  enabled: true
  
  # API metadata
  title: "My Generated API"
  version: "1.0.0"
  
  # Naming rules
  naming_rules:
    entity_case: "PascalCase"  # PascalCase, camelCase, snake_case
    route_case: "kebab-case"   # kebab-case, snake_case, camelCase
    pluralization: "standard"  # standard, none, custom
    
  # Generation options
  generate_crud: true
  infer_relationships: true
  merge_schemas: true

Naming Rules

Customize how entities and routes are named:

naming_rules:
  # Entity naming
  entity_case: "PascalCase"  # User, OrderItem
  entity_suffix: ""           # Optional suffix
  
  # Route naming
  route_case: "kebab-case"    # /api/users, /api/order-items
  route_prefix: "/api"        # Route prefix
  
  # Pluralization
  pluralization: "standard"   # users, orders
  custom_plurals:
    person: "people"
    child: "children"

CLI Commands

There are no CLI commands for Generative Schema Mode yet. The intended CLI would generate from one or more JSON files, set the API title and version, preview the generated schema without writing files, and optionally start a server with the result.

Programmatic Usage

Generate Ecosystem

#![allow(unused)]
fn main() {
use mockforge_core::generative_schema::{
    EcosystemGenerator, GenerationOptions, NamingRules
};
use serde_json::json;

// Example payloads
let payloads = vec![
    json!({
        "users": [
            {"id": 1, "name": "Alice", "email": "[email protected]"}
        ]
    })
];

// Generation options
let options = GenerationOptions {
    title: Some("My API".to_string()),
    version: Some("1.0.0".to_string()),
    naming_rules: NamingRules::default(),
    generate_crud: true,
    output_dir: Some("./generated".into()),
};

// Generate ecosystem
let result = EcosystemGenerator::generate_from_json(payloads, options).await?;

// Access generated spec
let spec = result.spec;
let entities = result.entities;
let routes = result.routes;
}

Entity Relationship Inference

MockForge automatically detects relationships from JSON structure:

One-to-Many (1:N)

Detected from foreign key patterns:

{
  "users": [{"id": 1, "name": "Alice"}],
  "posts": [{"id": 1, "user_id": 1, "title": "Post"}]
}

Detected Relationship:

  • User has many Post (via user_id)

Many-to-Many (N:N)

Detected from junction patterns:

{
  "users": [{"id": 1, "name": "Alice"}],
  "roles": [{"id": 1, "name": "admin"}],
  "user_roles": [
    {"user_id": 1, "role_id": 1}
  ]
}

Detected Relationship:

  • User has many Role through user_roles

Schema Merging

When generating from multiple JSON payloads, schemas are intended to be merged:

Merging Strategy:

  • Common fields are preserved
  • New fields are added
  • Type conflicts are resolved (prefer more specific types)
  • Relationships are merged

Preview and Edit

The intended workflow is to preview the generated schema (in the terminal or a browser) and edit it before deployment. There is no CLI for preview or edit yet. Once you have an OpenAPI file, you can serve it as usual:

mockforge serve --spec ./generated/openapi.yaml

Integration with VBR

Generated schemas are intended to integrate with VBR (there is no CLI option for this yet). The integration would create:

  • VBR entity definitions
  • Relationship mappings
  • Seed data from JSON

Use Cases

Rapid Prototyping

Quickly create mock APIs from example data. Until generative schema is exposed, mockforge quick serves sample JSON directly:

mockforge quick sample-responses.json

API Design

Design APIs by example, producing an OpenAPI spec from design mockups (planned).

Testing Data Generation

Generate test APIs with realistic data from sample payloads (planned).

Best Practices

  1. Provide Complete Examples: Include all fields you want in the generated schema
  2. Use Consistent Naming: Consistent naming in JSON helps with entity inference
  3. Include Relationships: Show relationships in JSON for automatic detection
  4. Preview Before Deploy: Always preview generated schemas before deployment
  5. Version Control: Commit generated schemas to version control

Troubleshooting

Entities Not Detected

  • Ensure JSON has a clear structure (arrays of objects)
  • Use consistent field names
  • Include ID fields for relationship detection

Routes Not Generated

  • Check that generate_crud is enabled
  • Verify entity names are valid
  • Review naming rules configuration

Relationships Not Inferred

  • Use standard foreign key naming (entity_id)
  • Include junction tables for many-to-many
  • Provide complete relationship data in JSON

Behavioral Economics Engine

Planned / not yet available. mockforge behavior-rule can write rules to config, but the rule engine is not yet attached to the request path, so rules do not affect responses. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Reality]

The Behavioral Economics Engine makes mocks react to real-world pressures like latency, load, pricing changes, fraud suspicion, and customer segments. This creates mocks that behave like real customer-driven systems, not just static endpoints.

Overview

Traditional mocks return fixed responses. The Behavioral Economics Engine adds intelligence that makes mocks adapt their behavior based on system conditions:

  • Cart conversion drops if latency exceeds 400ms
  • Bank declines transactions if prior balance checks failed
  • User churn increases after multiple 500 errors
  • Pricing changes affect purchase behavior
  • Fraud suspicion triggers additional verification

Key Concepts

Conditions

Conditions are triggers that evaluate system state:

  • Latency Threshold: Endpoint latency exceeds a threshold
  • Load Pressure: Requests per second exceeds a threshold
  • Pricing Change: Product pricing changes by a percentage
  • Fraud Suspicion: User’s risk score exceeds a threshold
  • Customer Segment: User belongs to a specific segment
  • Error Rate: Error rate for an endpoint exceeds a threshold

Actions

Actions are behaviors executed when conditions are met:

  • Modify Conversion Rate: Adjust success probability
  • Change Response Behavior: Modify response data
  • Trigger Chaos: Activate chaos scenarios
  • Adjust Latency: Increase/decrease response time
  • Change Error Rate: Modify error probability

Rules

Rules combine conditions and actions:

  • Declarative Rules: Simple if-then logic (YAML/JSON)
  • Scriptable Rules: Advanced logic (JavaScript/WASM)

Quick Start

Basic Configuration

# mockforge.yaml
behavioral_economics:
  enabled: true
  rules:
    - name: latency-conversion-impact
      condition:
        type: latency_threshold
        endpoint: "/api/checkout/*"
        threshold_ms: 400
      action:
        type: modify_conversion_rate
        multiplier: 0.8  # 20% drop in conversion
      priority: 100

Example: Cart Abandonment

behavioral_economics:
  enabled: true
  rules:
    - name: cart-abandonment-on-latency
      condition:
        type: latency_threshold
        endpoint: "/api/checkout/*"
        threshold_ms: 500
      action:
        type: modify_response
        field: "body.cart_status"
        value: "abandoned"
      priority: 200

Condition Types

Latency Threshold

Triggers when endpoint latency exceeds a threshold:

condition:
  type: latency_threshold
  endpoint: "/api/checkout/*"  # Pattern matching
  threshold_ms: 400

Use Cases:

  • Cart abandonment on slow checkout
  • User frustration on slow search
  • Timeout handling

Load Pressure

Triggers when requests per second exceed a threshold:

condition:
  type: load_pressure
  threshold_rps: 100.0

Use Cases:

  • Degraded service under load
  • Rate limiting activation
  • Circuit breaker patterns

Pricing Change

Triggers when product pricing changes:

condition:
  type: pricing_change
  product_id: "product-123"
  threshold: 0.1  # 10% change

Use Cases:

  • Purchase behavior changes
  • Cart abandonment on price increase
  • Surge pricing effects

Fraud Suspicion

Triggers when user’s fraud risk score exceeds threshold:

condition:
  type: fraud_suspicion
  user_id: "user-123"
  risk_score: 0.7  # 0.0 to 1.0

Use Cases:

  • Additional verification required
  • Transaction declines
  • Account restrictions

Customer Segment

Triggers when user belongs to a segment:

condition:
  type: customer_segment
  segment: "premium"

Use Cases:

  • Different service levels
  • Priority handling
  • Exclusive features

Error Rate

Triggers when error rate exceeds threshold:

condition:
  type: error_rate
  endpoint: "/api/payments/*"
  threshold: 0.05  # 5% error rate

Use Cases:

  • User churn after errors
  • Retry behavior changes
  • Fallback activation

Composite Conditions

Combine multiple conditions with logical operators:

condition:
  type: composite
  operator: and  # or, not
  conditions:
    - type: latency_threshold
      endpoint: "/api/checkout/*"
      threshold_ms: 400
    - type: load_pressure
      threshold_rps: 100.0

Action Types

Modify Conversion Rate

Adjusts the probability of successful operations:

action:
  type: modify_conversion_rate
  multiplier: 0.8  # 80% of normal conversion

Use Cases:

  • Cart abandonment on slow checkout
  • Purchase drop on high latency
  • Signup reduction on errors

Modify Response

Changes response data:

action:
  type: modify_response
  field: "body.status"
  value: "pending"

Use Cases:

  • Status changes based on conditions
  • Data mutations
  • State transitions

Trigger Chaos

Activates chaos scenarios:

action:
  type: trigger_chaos
  scenario: "high-error-rate"
  duration_seconds: 60

Use Cases:

  • Simulating incidents
  • Testing resilience
  • Chaos engineering

Adjust Latency

Modifies response latency:

action:
  type: adjust_latency
  multiplier: 1.5  # 50% increase
  max_ms: 2000

Use Cases:

  • Degraded performance simulation
  • Network condition emulation
  • Timeout testing

Change Error Rate

Modifies error probability:

action:
  type: change_error_rate
  multiplier: 2.0  # Double error rate
  error_codes: [500, 503]

Use Cases:

  • Error spike simulation
  • Failure testing
  • Resilience validation

Advanced: Scriptable Rules

For complex logic, use JavaScript/WASM scripts:

behavioral_economics:
  enabled: true
  rules:
    - name: complex-fraud-detection
      rule_type: scriptable
      script: |
        function evaluate(context) {
          const latency = context.latency;
          const load = context.load_rps;
          const fraudScore = context.fraud_score;
          
          if (latency > 400 && load > 100 && fraudScore > 0.7) {
            return {
              action: "decline_transaction",
              reason: "High risk under load"
            };
          }
          return null;
        }
      priority: 1000

Real-World Examples

E-Commerce: Cart Conversion

behavioral_economics:
  rules:
    - name: cart-conversion-drop
      condition:
        type: latency_threshold
        endpoint: "/api/checkout/*"
        threshold_ms: 400
      action:
        type: modify_conversion_rate
        multiplier: 0.7  # 30% drop
      priority: 100

Result: When checkout latency exceeds 400ms, only 70% of carts convert (vs normal 90%).

Fintech: Transaction Declines

behavioral_economics:
  rules:
    - name: decline-on-failed-balance-check
      condition:
        type: composite
        operator: and
        conditions:
          - type: error_rate
            endpoint: "/api/balance/*"
            threshold: 0.1
          - type: fraud_suspicion
            risk_score: 0.6
      action:
        type: modify_response
        field: "body.status"
        value: "declined"
        reason: "Balance check failed"
      priority: 200

Result: Transactions are declined if balance checks fail and fraud risk is high.

SaaS: User Churn

behavioral_economics:
  rules:
    - name: churn-after-multiple-errors
      condition:
        type: error_rate
        endpoint: "/api/*"
        threshold: 0.05  # 5% error rate
      action:
        type: modify_response
        field: "body.churn_risk"
        value: "high"
      priority: 150

Result: User churn risk increases after experiencing multiple errors.

Integration with Other Features

The Behavioral Economics Engine integrates with:

  • Smart Personas: Persona traits influence condition evaluation
  • Chaos Lab: Actions can trigger chaos scenarios
  • Reality Continuum: Behaviors respect reality levels
  • Scenarios: Rules can be scenario-specific
  • Time Travel: Conditions respect virtual time

Configuration Reference

Full Configuration

behavioral_economics:
  enabled: true
  update_interval_ms: 1000  # How often to evaluate rules
  rules:
    - name: rule-name
      rule_type: declarative  # or scriptable
      condition:
        # Condition configuration
      action:
        # Action configuration
      priority: 100  # Higher = evaluated first
      enabled: true

Rule Priority

Rules are evaluated in priority order (highest first). The first matching rule’s action is executed.

Best Practices

  1. Start Simple: Use declarative rules for 80% of use cases
  2. Test Incrementally: Add one rule at a time and test
  3. Monitor Impact: Track how rules affect system behavior
  4. Document Rules: Document why each rule exists
  5. Version Control: Keep rules in version control

Troubleshooting

Rules Not Triggering

  • Check condition thresholds (may be too high/low)
  • Verify endpoint patterns match actual endpoints
  • Check rule priority (higher priority rules may override)
  • Enable debug logging: behavioral_economics.debug: true

Unexpected Behavior

  • Review rule priority order
  • Check for conflicting rules
  • Verify condition evaluation logic
  • Test rules in isolation

World State Engine

Planned / not yet available. A read-only /api/world-state/* API and UI page exist, but no data sources are registered yet (snapshots are empty), and there is no mockforge world-state CLI, no snapshot-creation endpoint, no time-travel queries, and no GraphML/DOT export. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Reality][DevX]

The World State Engine unifies all MockForge state systems into a single “world state” visualization. Think of it as a miniature game engine for your backend—a unified view of personas, lifecycle, reality, time, multi-protocol state, behavior trees, generative schemas, recorded data, and AI modifiers.

Overview

The World State Engine aggregates and visualizes:

  • Personas: Persona profiles, relationships, and graphs
  • Lifecycle: Lifecycle states, transitions, and time-based changes
  • Reality: Reality levels, continuum ratios, and chaos rules
  • Time: Virtual clock state, scheduled events, and time scale
  • Multi-Protocol: Protocol-specific state, sessions, and entity state
  • Behavior: Behavior trees, rules, and AI modifiers
  • Schemas: Generative schema definitions and entity relationships
  • Recorded Data: Recorded requests/responses, fixtures, and replay state
  • AI Modifiers: AI response configurations and modifiers

Key Features

  • Unified State Aggregation: Collects state from all MockForge subsystems
  • Graph Visualization: Represents state as nodes and edges for visualization
  • Real-time Updates: Streams state changes in real-time
  • Time Travel: View state at any point in time
  • Query Interface: Flexible querying of state with filters
  • Export Capabilities: Export state in various formats (JSON, GraphML, DOT)

Usage

There is no mockforge world-state CLI yet. The HTTP server exposes a read-only API under /api/world-state:

# Current snapshot (optional ?workspace=, ?layers=, ?node_types= filters)
curl http://localhost:3000/api/world-state/snapshot

# Current state as a graph (nodes and edges)
curl http://localhost:3000/api/world-state/graph

# Available layers
curl http://localhost:3000/api/world-state/layers

A WebSocket stream of state changes is available at /api/world-state/stream, and the Admin UI has a World State page. Because no data sources are registered yet, these currently return empty state.

State Layers

Personas Layer

Persona profiles and relationships:

{
  "layer": "personas",
  "nodes": [
    {
      "id": "persona:premium-001",
      "type": "persona",
      "data": {
        "traits": {...},
        "relationships": [...]
      }
    }
  ],
  "edges": [
    {
      "from": "persona:premium-001",
      "to": "order:123",
      "type": "has_orders"
    }
  ]
}

Reality Layer

Reality levels and continuum ratios:

{
  "layer": "reality",
  "state": {
    "reality_level": 3,
    "continuum_ratio": 0.5,
    "chaos_rules": [...]
  }
}

Time Layer

Virtual clock and scheduled events:

{
  "layer": "time",
  "state": {
    "virtual_time": "2025-01-27T10:00:00Z",
    "time_scale": 1.0,
    "scheduled_events": [...]
  }
}

Protocols Layer

Protocol-specific state:

{
  "layer": "protocols",
  "state": {
    "http": {
      "sessions": [...],
      "connections": [...]
    },
    "websocket": {
      "connections": [...],
      "subscriptions": [...]
    }
  }
}

Query Interface

The intended design supports filtering by layer, by criteria (persona, reality level, time), and combining several filters. There is no mockforge world-state CLI for this yet. The existing read-only API accepts a structured filter body:

curl -X POST http://localhost:3000/api/world-state/query \
  -H "Content-Type: application/json" \
  -d '{"layers": ["personas", "reality"], "node_types": ["persona"], "include_edges": true}'

Free-form criteria filters (for example reality_level>=3) are not implemented.

Time Travel

Viewing world state at an arbitrary point in time is planned but not implemented. Previously captured snapshots can be fetched by ID with GET /api/world-state/snapshot/{id}.

Export Formats

Exporting world state as JSON, GraphML, or DOT is planned. There is no export command yet; GET /api/world-state/graph returns the current graph as JSON.

Real-World Example

E-Commerce World State

{
  "workspace_id": "ecommerce-123",
  "snapshot_time": "2025-01-27T10:00:00Z",
  "layers": {
    "personas": {
      "nodes": [
        {
          "id": "persona:premium-001",
          "type": "persona",
          "data": {
            "traits": {"tier": "premium"},
            "lifecycle_state": "active"
          }
        },
        {
          "id": "order:456",
          "type": "order",
          "data": {
            "status": "pending",
            "total": 99.99
          }
        }
      ],
      "edges": [
        {
          "from": "persona:premium-001",
          "to": "order:456",
          "type": "has_orders"
        }
      ]
    },
    "reality": {
      "reality_level": 3,
      "continuum_ratio": 0.5,
      "chaos_rules": []
    },
    "time": {
      "virtual_time": "2025-01-27T10:00:00Z",
      "time_scale": 1.0
    }
  }
}

Best Practices

  1. Regular Snapshots: Take snapshots at key points
  2. Query Efficiently: Use filters to query only needed layers
  3. Visualize: Use graph visualization to understand relationships
  4. Time Travel: Use time travel to debug temporal issues
  5. Export for Analysis: Export state for external analysis

Performance Mode (Load Simulation)

Planned / not yet available. /api/performance/* and a UI page exist, but the simulator is not yet on the request path (it neither generates load nor shapes responses), and there is no mockforge performance CLI. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [DevX]

Performance Mode provides lightweight load simulation for running scenarios at N RPS, simulating bottlenecks, recording latencies, and observing how responses change under load. This is NOT true load testing—it’s realistic behavior simulation under stress testing conditions.

Overview

Performance Mode enables:

  • Run scenarios at n RPS: Control request rate
  • Simulate bottlenecks: Add artificial delays
  • Record latencies: Track response times
  • Observe behavior changes: See how responses change under load

Quick Start

There is no mockforge performance CLI. Performance mode is driven through the HTTP API.

Via API

# Start performance mode
POST /api/performance/start
{
  "initial_rps": 100,
  "bottlenecks": [
    {
      "bottleneck_type": "network",
      "severity": 0.5,
      "endpoint_pattern": "/api/checkout/*"
    }
  ]
}

# Stop it
POST /api/performance/stop

Other endpoints: GET /api/performance/status, GET /api/performance/snapshot, POST /api/performance/rps, and POST/DELETE /api/performance/bottlenecks.

RPS Profiles

Constant RPS

Maintain constant requests per second:

rps_profile:
  type: constant
  rps: 100

Ramp Profile

Gradually increase RPS:

rps_profile:
  type: ramp
  start_rps: 10
  end_rps: 100
  duration_seconds: 60

Spike Profile

Sudden spike in RPS:

rps_profile:
  type: spike
  base_rps: 50
  spike_rps: 200
  spike_duration_seconds: 10
  spike_interval_seconds: 60

Bottleneck Simulation

Endpoint Bottlenecks

Add delays to specific endpoints:

bottlenecks:
  - endpoint: "/api/checkout/*"
    delay_ms: 500
    probability: 1.0  # Always delay
  - endpoint: "/api/payments/*"
    delay_ms: 1000
    probability: 0.5  # 50% chance

Database Bottlenecks

Simulate database slowdowns:

bottlenecks:
  - type: database
    delay_ms: 200
    probability: 0.3

Network Bottlenecks

Simulate network conditions:

bottlenecks:
  - type: network
    latency_ms: 100
    packet_loss: 0.01

Latency Recording

Automatic Recording

Latencies are automatically recorded:

{
  "endpoint": "/api/users/{id}",
  "method": "GET",
  "latency_ms": 150,
  "status_code": 200,
  "timestamp": "2025-01-27T10:00:00Z"
}

Latency Analysis

Analyze recorded latencies:

# Get latency statistics
GET /api/performance/snapshot

# Response:
{
  "stats": {
    "mean_latency_ms": 150,
    "p50_latency_ms": 140,
    "p95_latency_ms": 250,
    "p99_latency_ms": 400,
    "max_latency_ms": 500
  }
}

Response Changes Under Load

Behavioral Economics Integration

Responses may change under load due to behavioral economics:

# Under normal load
GET /api/checkout → 200 OK, conversion: 90%

# Under high load (latency > 400ms)
GET /api/checkout → 200 OK, conversion: 70%  # 20% drop

Error Rate Increases

Error rates may increase under load:

# Normal load
Error rate: 1%

# High load
Error rate: 5%  # Increased errors

Usage Examples

There is no mockforge performance CLI. The simulator is controlled through the /api/performance endpoints on the HTTP server.

Example 1: Constant Load

# Start at a constant 100 RPS
curl -X POST http://localhost:3000/api/performance/start \
  -H "Content-Type: application/json" \
  -d '{"initial_rps": 100}'

# Monitor
curl http://localhost:3000/api/performance/snapshot

Example 2: Ramp Load

# Ramp from 10 to 100 RPS using profile stages
curl -X POST http://localhost:3000/api/performance/start \
  -H "Content-Type: application/json" \
  -d '{
    "initial_rps": 10,
    "rps_profile": {
      "name": "ramp",
      "stages": [
        {"duration_secs": 30, "target_rps": 10},
        {"duration_secs": 30, "target_rps": 100}
      ]
    }
  }'

# Or change the target RPS of a running simulation
curl -X POST http://localhost:3000/api/performance/rps \
  -H "Content-Type: application/json" \
  -d '{"target_rps": 100}'

Example 3: With Bottlenecks

# Add a database bottleneck on checkout endpoints
curl -X POST http://localhost:3000/api/performance/bottlenecks \
  -H "Content-Type: application/json" \
  -d '{"bottleneck": {"bottleneck_type": "database", "severity": 0.5, "endpoint_pattern": "/api/checkout/*"}}'

# Clear all bottlenecks
curl -X DELETE http://localhost:3000/api/performance/bottlenecks

Configuration

Performance Mode Config

# mockforge.yaml
performance:
  enabled: true
  default_rps: 100
  max_latency_samples: 10000
  max_latency_age_seconds: 300

RPS Controller

performance:
  rps_controller:
    type: token_bucket
    capacity: 1000
    refill_rate: 100  # per second

Best Practices

  1. Start Low: Begin with low RPS and increase gradually
  2. Monitor Latencies: Watch latency percentiles
  3. Test Bottlenecks: Simulate realistic bottlenecks
  4. Observe Behavior: Watch how responses change
  5. Not True Load Testing: This is simulation, not production load testing

Synthetic → Recorded Drift Learning

Planned / not yet available. mockforge drift-learning enable, disable and status can set configuration, but the learning engine is not yet wired into request handling, so no drift is learned at runtime. There is no CLI for viewing or resetting learned patterns. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [Reality]

The Drift Learning System allows mocks to gradually learn from recorded traffic and adapt their behavior. Instead of static synthetic data, mocks can evolve to match real-world patterns observed in traffic.

Overview

Drift Learning extends the DataDriftEngine with learning capabilities that enable:

  • Traffic Pattern Learning: Mocks learn from recorded request patterns
  • Persona Behavior Adaptation: Personas adapt based on observed request patterns
  • Configurable Learning Rate: Control how quickly mocks learn
  • Opt-in Per Endpoint/Persona: Enable learning selectively
  • Pattern Decay: Old patterns fade if upstream patterns reverse

Key Concepts

Learning Modes

Drift Learning supports three learning modes:

Behavioral Learning

Adapts to behavior patterns observed in traffic:

  • Request Sequences: Learns common request sequences
  • User Flows: Adapts to typical user workflows
  • Interaction Patterns: Learns how users interact with the API

Use Case: When you want mocks to reflect real user behavior patterns.

Statistical Learning

Adapts to statistical patterns in traffic:

  • Latency Patterns: Learns typical latency distributions
  • Error Rates: Adapts to observed error rate patterns
  • Request Frequency: Learns request frequency patterns

Use Case: When you want mocks to match statistical properties of real traffic.

Hybrid Learning

Combines behavioral and statistical learning:

  • Best of Both: Uses both behavioral and statistical patterns
  • Balanced Adaptation: Balances behavior and statistics
  • Comprehensive Learning: Most comprehensive learning mode

Use Case: When you want the most realistic mocks possible.

Learning Configuration

drift_learning:
  enabled: true
  mode: hybrid  # behavioral, statistical, or hybrid
  sensitivity: 0.2  # How quickly mocks learn (0.0-1.0)
  decay: 0.05  # How quickly old patterns fade (0.0-1.0)
  min_samples: 10  # Minimum samples before learning starts
  update_interval: 60s  # How often to update learned patterns
  persona_adaptation: true  # Enable persona-specific learning
  traffic_mirroring: true  # Enable traffic pattern mirroring

How It Works

1. Traffic Recording

The system records traffic patterns:

  • Request Sequences: Tracks sequences of requests
  • Response Patterns: Records response patterns
  • Timing Information: Captures latency and timing data
  • Error Patterns: Tracks error occurrences

2. Pattern Analysis

Recorded traffic is analyzed to identify patterns:

  • Behavioral Patterns: User behavior sequences
  • Statistical Patterns: Latency, error rate distributions
  • Persona Patterns: Persona-specific behavior patterns

3. Learning Application

Learned patterns are applied to mocks:

  • Gradual Adaptation: Mocks gradually adapt to learned patterns
  • Confidence Scoring: Patterns are scored by confidence
  • Decay Handling: Low-confidence patterns fade over time

4. Pattern Updates

Patterns are updated periodically:

  • Update Interval: Configurable update frequency
  • Minimum Samples: Requires minimum samples before learning
  • Confidence Threshold: Only high-confidence patterns are applied

Usage

Enable Drift Learning

# mockforge.yaml
drift_learning:
  enabled: true
  mode: hybrid
  sensitivity: 0.2
  decay: 0.05
  min_samples: 10
  update_interval: 60s

Per-Endpoint Learning

Enable learning for specific endpoints:

drift_learning:
  enabled: true
  endpoint_learning:
    "/api/users/*": true  # Enable for user endpoints
    "/api/orders/*": true  # Enable for order endpoints
    "/api/payments/*": false  # Disable for payment endpoints

Per-Persona Learning

Enable learning for specific personas:

drift_learning:
  enabled: true
  persona_adaptation: true
  persona_learning:
    "premium-customer": true  # Enable for premium customers
    "regular-customer": true  # Enable for regular customers
    "admin": false  # Disable for admins

CLI Commands

# Enable drift learning (and set the learning mode)
mockforge drift-learning enable --mode hybrid --sensitivity 0.2 --min-samples 10

# Show current drift learning configuration
mockforge drift-learning status

# Enable learning for a specific endpoint or persona
mockforge drift-learning endpoint "/api/users/*" --enable
mockforge drift-learning persona premium-customer --enable

# Disable drift learning
mockforge drift-learning disable

There is no CLI yet for viewing or resetting learned patterns.

Learning Parameters

Sensitivity

Controls how quickly mocks learn from patterns:

  • Low (0.1): Slow, conservative learning
  • Medium (0.2): Balanced learning rate (default)
  • High (0.5): Fast, aggressive learning

Recommendation: Start with 0.2 and adjust based on results.

Decay

Controls how quickly old patterns fade:

  • Low (0.01): Patterns persist longer
  • Medium (0.05): Balanced decay (default)
  • High (0.1): Patterns fade quickly

Recommendation: Use 0.05 for most cases.

Minimum Samples

Minimum number of samples required before learning starts:

  • Low (5): Learn from few samples (may be noisy)
  • Medium (10): Balanced threshold (default)
  • High (50): Require many samples (more stable)

Recommendation: Use 10 for most cases, increase if patterns are noisy.

Real-World Examples

Example 1: E-Commerce Checkout Flow

Scenario: Learn from real checkout patterns

drift_learning:
  enabled: true
  mode: behavioral
  endpoint_learning:
    "/api/checkout/*": true
  persona_adaptation: true

Result: Mocks learn the typical checkout flow sequence and adapt responses accordingly.

Example 2: API Latency Patterns

Scenario: Learn latency patterns from real traffic

drift_learning:
  enabled: true
  mode: statistical
  endpoint_learning:
    "/api/*": true
  sensitivity: 0.3

Result: Mocks adapt their latency to match observed latency distributions.

Example 3: Persona-Specific Behavior

Scenario: Learn persona-specific behavior patterns

drift_learning:
  enabled: true
  mode: hybrid
  persona_adaptation: true
  persona_learning:
    "premium-customer": true
    "regular-customer": true

Result: Mocks learn different behavior patterns for different personas.

Traffic Pattern Mirroring

When traffic_mirroring is enabled, mocks mirror observed traffic patterns:

  • Request Frequency: Mirrors request frequency patterns
  • Request Sequences: Mirrors common request sequences
  • Timing Patterns: Mirrors timing patterns
  • Error Patterns: Mirrors error occurrence patterns

Configuration

drift_learning:
  enabled: true
  traffic_mirroring: true
  mode: hybrid

Persona Behavior Adaptation

When persona_adaptation is enabled, personas adapt based on observed behavior:

  • Behavior Patterns: Personas learn behavior patterns
  • Request Patterns: Personas learn request patterns
  • Response Patterns: Personas learn response patterns

Configuration

drift_learning:
  enabled: true
  persona_adaptation: true
  persona_learning:
    "premium-customer": true
    "regular-customer": true

Best Practices

  1. Start Conservative: Begin with low sensitivity and high min_samples
  2. Monitor Patterns: Regularly review learned patterns
  3. Selective Learning: Enable learning only for endpoints/personas that need it
  4. Test Incrementally: Enable learning for one endpoint at a time
  5. Review Confidence: Only apply high-confidence patterns
  6. Reset When Needed: Reset learned patterns if they become inaccurate

Troubleshooting

Mocks Not Learning

  • Check Enabled: Verify enabled: true
  • Check Samples: Ensure minimum samples are reached
  • Check Confidence: Low-confidence patterns may not be applied
  • Check Endpoint/Persona: Verify learning is enabled for the endpoint/persona

Patterns Too Aggressive

  • Lower Sensitivity: Reduce sensitivity value
  • Increase Min Samples: Require more samples before learning
  • Increase Decay: Make patterns fade faster

Patterns Not Updating

  • Check Update Interval: Verify update interval is reasonable
  • Check Samples: Ensure new samples are being recorded
  • Check Confidence: Low-confidence patterns may not update

Zero-Config Mode (Runtime Daemon)

Planned / not yet available. The runtime daemon exists as the mockforge-runtime-daemon crate behind an optional build feature that the released mockforge binary does not enable; there is no --runtime-daemon flag, and the runtime_daemon: config key shown below does not exist (in a feature-enabled build the daemon is configured only through MOCKFORGE_RUNTIME_DAEMON_* environment variables). This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [DevX]

Zero-Config Mode provides the “invisible mock server” experience. When you hit an endpoint that doesn’t exist, MockForge automatically creates a mock, generates types, creates client stubs, and sets up scenarios—all without manual configuration.

Overview

The Runtime Daemon is a background process that:

  • Detects when you hit an endpoint that doesn’t exist (404)
  • Automatically creates a mock endpoint
  • Generates types (TypeScript, JSON Schema)
  • Generates client stubs (React, Vue, etc.)
  • Updates OpenAPI schema
  • Creates example responses
  • Sets up scenarios

This is “mock server in your shadow”—an AI-assisted backend-on-demand.

Quick Start

Enable Zero-Config Mode

There is no --runtime-daemon flag. In a build that enables the runtime-daemon feature of mockforge-http (the released binary does not), the daemon is turned on with an environment variable:

MOCKFORGE_RUNTIME_DAEMON_ENABLED=true mockforge serve

Configuration

# mockforge.yaml
runtime_daemon:
  enabled: true
  auto_create_on_404: true
  ai_generation: true  # Use AI to generate intelligent responses
  generate_types: true  # Generate TypeScript/JSON Schema
  generate_client_stubs: true  # Generate client code
  update_openapi: true  # Update OpenAPI schema
  create_scenario: true  # Create scenarios automatically
  exclude_patterns:
    - "/health"
    - "/metrics"
    - "/__mockforge/*"

How It Works

1. Detection

When a request hits a non-existent endpoint (404), the daemon detects it:

GET /api/users/123 → 404 Not Found
→ Runtime Daemon detects 404
→ Analyzes request (method, path, headers, body)

2. Auto-Generation

The daemon automatically:

  1. Creates Mock Endpoint

    • Analyzes request to infer response structure
    • Uses AI to generate intelligent response
    • Sets appropriate status code
  2. Generates Types (if enabled)

    • TypeScript types
    • JSON Schema
    • Saved to generated/types/
  3. Generates Client Stubs (if enabled)

    • React hooks
    • Vue composables
    • Angular services
    • Saved to generated/clients/
  4. Updates OpenAPI Schema (if enabled)

    • Adds endpoint to OpenAPI spec
    • Infers request/response schemas
    • Updates openapi.json
  5. Creates Scenario (if enabled)

    • Basic scenario for the endpoint
    • Includes example request/response
    • Saved to scenarios/

3. Response

The next request to the same endpoint gets the auto-generated mock:

GET /api/users/123 → 200 OK
{
  "id": "123",
  "name": "John Doe",
  "email": "[email protected]"
}

Configuration Options

Auto-Create on 404

runtime_daemon:
  auto_create_on_404: true  # Create mocks automatically

AI Generation

runtime_daemon:
  ai_generation: true  # Use AI for intelligent responses

When enabled, AI generates realistic responses based on:

  • Endpoint path patterns
  • Request body structure
  • Domain context
  • Existing mocks

Type Generation

runtime_daemon:
  generate_types: true
  types_output_dir: "./generated/types"

Generates:

  • TypeScript types
  • JSON Schema
  • Go types
  • Rust types

Client Stub Generation

runtime_daemon:
  generate_client_stubs: true
  clients_output_dir: "./generated/clients"
  client_frameworks:
    - react
    - vue
    - angular

OpenAPI Updates

runtime_daemon:
  update_openapi: true
  openapi_path: "./openapi.json"

Automatically updates OpenAPI spec with new endpoints.

Scenario Creation

runtime_daemon:
  create_scenario: true
  scenarios_output_dir: "./scenarios"

Creates basic scenarios for auto-generated endpoints.

Example Workflow

1. Start Development

# Start MockForge with runtime daemon (requires a runtime-daemon build)
MOCKFORGE_RUNTIME_DAEMON_ENABLED=true mockforge serve

2. Make Request

# Frontend makes request to non-existent endpoint
curl http://localhost:3000/api/products/123
# → 404 Not Found

3. Auto-Generation

The daemon automatically:

  • Creates mock for /api/products/{id}
  • Generates TypeScript types
  • Creates React hook
  • Updates OpenAPI spec
  • Creates scenario

4. Use Generated Code

// Generated React hook
import { useProduct } from './generated/clients/react';

function ProductPage({ id }) {
  const { data, loading } = useProduct(id);
  // ...
}

Excluding Patterns

Exclude certain paths from auto-generation:

runtime_daemon:
  exclude_patterns:
    - "/health"
    - "/metrics"
    - "/__mockforge/*"
    - "/api/internal/*"

Workspace Integration

The daemon saves generated artifacts to your workspace:

workspace/
├── mocks/
│   └── auto-generated/
│       └── api-products-{id}.yaml
├── generated/
│   ├── types/
│   │   └── Product.ts
│   └── clients/
│       └── react/
│           └── useProduct.ts
├── scenarios/
│   └── auto-products-{id}.yaml
└── openapi.json  # Updated automatically

AI-Powered Generation

When AI generation is enabled, the daemon uses AI to create intelligent responses:

Request Analysis

POST /api/orders
{
  "product_id": "123",
  "quantity": 2
}

AI-Generated Response

{
  "id": "order-456",
  "product_id": "123",
  "quantity": 2,
  "status": "pending",
  "total": 99.98,
  "created_at": "2025-01-27T10:00:00Z"
}

The AI infers:

  • Order structure from request
  • Realistic IDs and timestamps
  • Calculated fields (total)
  • Appropriate status values

Best Practices

  1. Start with AI Generation: Let AI create intelligent responses
  2. Review Generated Mocks: Check auto-generated mocks for accuracy
  3. Refine Over Time: Update mocks as you learn more about the API
  4. Version Control: Commit generated artifacts to Git
  5. Exclude Internal Endpoints: Don’t auto-generate for internal APIs

Troubleshooting

Mocks Not Created

  • Check auto_create_on_404 is enabled
  • Verify endpoint isn’t in exclude_patterns
  • Check the daemon is enabled: MOCKFORGE_RUNTIME_DAEMON_ENABLED=true (requires a runtime-daemon build)

Generated Code Issues

  • Review generated types for accuracy
  • Update OpenAPI spec manually if needed
  • Regenerate: mockforge generate --spec openapi.json

AI Generation Quality

  • Provide more context in existing mocks
  • Use domain-specific reality profiles
  • Adjust AI model/temperature settings

API Architecture Critique

Planned / not yet available. The critique engine and AI Studio panel exist, but the backend API is not mounted yet and there is no mockforge ai critique command. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [AI]

API Architecture Critique feeds entire API schemas into an LLM and produces comprehensive analysis including anti-pattern detection, redundancy detection, poor naming, emotional tone assessment, and recommended restructuring. This positions MockForge as an API Architect AI.

Overview

Beyond structural validation, API Architecture Critique provides:

  • Anti-Pattern Detection: REST violations, inconsistent naming, poor resource modeling
  • Redundancy Detection: Duplicate endpoints, overlapping functionality
  • Naming Quality Assessment: Inconsistent conventions, unclear names, abbreviations
  • Emotional Tone Analysis: Error messages that are too vague, technical, or unfriendly
  • Restructuring Recommendations: Better resource hierarchy, consolidation opportunities

Usage

CLI Commands

There is no CLI for API critique yet. The intended command would critique a whole schema, optionally narrowed to focus areas (anti-patterns, naming, tone) or to a single endpoint.

API Usage

There is no HTTP endpoint for API critique yet. The intended request would send the schema, its type (OpenAPI, GraphQL, or Protobuf), and the focus areas to analyze.

UI Usage

Access via AI Studio page:

  1. Navigate to AI Studio
  2. Select “API Critique”
  3. Upload OpenAPI/GraphQL/Protobuf schema
  4. Select focus areas
  5. Review critique results

Critique Results

Example Critique

{
  "anti_patterns": [
    {
      "pattern_type": "rest_violation",
      "severity": "high",
      "location": "/api/users/{id}/delete",
      "description": "DELETE endpoint should use DELETE method, not POST",
      "suggestion": "Change to DELETE /api/users/{id}",
      "example": "POST /api/users/{id}/delete → DELETE /api/users/{id}"
    }
  ],
  "redundancies": [
    {
      "redundancy_type": "duplicate_endpoint",
      "severity": "medium",
      "affected_items": [
        "/api/users/list",
        "/api/users"
      ],
      "description": "Both endpoints return user lists",
      "suggestion": "Consolidate to /api/users"
    }
  ],
  "naming_issues": [
    {
      "issue_type": "inconsistent_convention",
      "severity": "low",
      "location": "user_id",
      "current_name": "user_id",
      "description": "Inconsistent: some fields use 'id', others use 'Id'",
      "suggestion": "Standardize to 'id' or 'Id'"
    }
  ],
  "tone_analysis": {
    "overall_tone": "technical",
    "error_message_issues": [
      {
        "issue_type": "too_vague",
        "severity": "medium",
        "location": "400 error",
        "current_text": "Bad request",
        "description": "Error message is too vague",
        "suggestion": "Provide specific error details: 'Invalid user ID format'"
      }
    ],
    "recommendations": [
      "Make error messages more user-friendly",
      "Provide actionable error details"
    ]
  },
  "restructuring": {
    "hierarchy_improvements": [
      {
        "current": "/api/users/{id}/orders/{order_id}",
        "suggested": "/api/orders/{order_id}?user_id={id}",
        "rationale": "Orders are top-level resources, not nested under users",
        "impact": "medium"
      }
    ],
    "consolidation_opportunities": [
      {
        "items": ["/api/users/list", "/api/users"],
        "description": "Duplicate user listing endpoints",
        "suggestion": "Use single /api/users endpoint with query parameters",
        "benefits": ["Simpler API", "Less maintenance"]
      }
    ]
  },
  "overall_score": 72.5,
  "summary": "API has good structure but needs improvements in REST compliance and error messaging."
}

Focus Areas

Anti-Patterns

Detects REST violations and design issues:

  • REST Violations: Wrong HTTP methods, non-RESTful patterns
  • Inconsistent Naming: Mixed naming conventions
  • Poor Resource Modeling: Incorrect resource hierarchy

Redundancy

Detects duplicate or overlapping functionality:

  • Duplicate Endpoints: Multiple endpoints doing the same thing
  • Overlapping Functionality: Endpoints with significant overlap

Naming Quality

Assesses naming consistency and clarity:

  • Inconsistent Conventions: Mixed naming styles
  • Unclear Names: Ambiguous or confusing names
  • Abbreviations: Overuse of abbreviations

Emotional Tone

Analyzes user-facing text quality:

  • Error Messages: Too vague, technical, or unfriendly
  • Descriptions: Unclear or unhelpful
  • User-Facing Text: Tone and clarity issues

Restructuring

Recommends structural improvements:

  • Hierarchy Improvements: Better resource organization
  • Consolidation Opportunities: Endpoints that can be merged
  • Resource Modeling: Better resource design

Real-World Examples

Example 1: REST Violation

Anti-Pattern Detected:

POST /api/users/{id}/delete

Issue: DELETE operation should use DELETE method.

Suggestion:

DELETE /api/users/{id}

Example 2: Redundancy

Redundancy Detected:

GET /api/users/list
GET /api/users

Issue: Both endpoints return user lists.

Suggestion: Consolidate to GET /api/users with query parameters.

Example 3: Naming Inconsistency

Issue Detected:

  • Some fields: user_id, order_id
  • Other fields: userId, orderId

Suggestion: Standardize to one convention (e.g., user_id).

Example 4: Error Message Tone

Issue Detected:

{
  "error": "Bad request"
}

Issue: Too vague, not actionable.

Suggestion:

{
  "error": "Invalid user ID format. Expected UUID.",
  "code": "INVALID_USER_ID"
}

Configuration

Enable API Critique

# mockforge.yaml
ai_studio:
  api_critique:
    enabled: true
    default_focus_areas:
      - anti-patterns
      - redundancy
      - naming
      - tone
      - restructuring

LLM Configuration

ai_studio:
  api_critique:
    enabled: true
    llm:
      provider: openai
      model: gpt-4
      temperature: 0.3

Best Practices

  1. Run Early: Critique APIs during design phase
  2. Focus Areas: Select relevant focus areas
  3. Review Recommendations: AI suggestions are helpful but review manually
  4. Iterate: Use critique to improve API design
  5. Track Scores: Monitor overall scores over time

Natural Language to System Generation

Planned / not yet available. The system generator and AI Studio panel exist, but the backend API is not mounted yet and there is no mockforge ai generate-system command. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [AI]

Natural Language to System Generation allows you to describe your product in natural language and MockForge generates an entire backend system including endpoints, personas, lifecycle states, WebSocket topics, failure scenarios, and more.

Overview

Instead of manually creating APIs, describe your product and get:

  • 20-30 REST endpoints (OpenAPI 3.1 spec)
  • 4-5 personas (based on roles)
  • 6-10 lifecycle states (state machines)
  • WebSocket topics (if real-time features mentioned)
  • Payment failure scenarios
  • Surge pricing chaos profiles
  • Full OpenAPI specification
  • Mock backend configuration (mockforge.yaml)
  • GraphQL schema (optional)
  • Typings (TypeScript/Go/Rust)
  • CI pipeline templates (GitHub Actions, GitLab CI)

This becomes a way to bootstrap an entire startup backend.

Quick Start

Basic Usage

There is no CLI for system generation yet. The intended command would take a product description such as “I’m building a ride-sharing app with drivers, riders, trips, payments, live-location updates, pricing, and surge events.” and generate the artifacts listed above.

Via AI Studio

  1. Navigate to AI Studio
  2. Select “System Generation”
  3. Enter your product description
  4. Select output formats
  5. Generate system

Example: Ride-Sharing App

Input

I'm building a ride-sharing app with drivers, riders, trips, payments, 
live-location updates, pricing, and surge events.

Generated Output

OpenAPI Specification

openapi: 3.1.0
info:
  title: Ride-Sharing API
  version: 1.0.0
paths:
  /api/drivers:
    get:
      summary: List drivers
      responses:
        '200':
          description: List of drivers
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Driver'
  /api/riders:
    get:
      summary: List riders
      # ... more endpoints
  /api/trips:
    post:
      summary: Create trip
      # ... more endpoints
  /api/payments:
    post:
      summary: Process payment
      # ... more endpoints

Personas

personas:
  - id: driver:premium-001
    name: Premium Driver
    domain: ridesharing
    traits:
      vehicle_type: premium
      rating: 4.9
      total_trips: 500
  - id: rider:frequent-002
    name: Frequent Rider
    domain: ridesharing
    traits:
      ride_frequency: high
      preferred_payment: credit_card

Lifecycle States

lifecycles:
  - entity: trip
    states:
      - requested
      - matched
      - in_progress
      - completed
      - cancelled
    transitions:
      - from: requested
        to: matched
        condition: driver_accepts
      - from: matched
        to: in_progress
        condition: trip_starts

WebSocket Topics

websocket_topics:
  - topic: location_updates
    event_types:
      - driver_location
      - rider_location
  - topic: trip_status
    event_types:
      - trip_requested
      - trip_matched
      - trip_completed
  - topic: surge_alerts
    event_types:
      - surge_started
      - surge_ended

Chaos Profiles

chaos_profiles:
  - name: payment_failure
    type: payment_failure
    config:
      failure_scenarios:
        - insufficient_funds
        - card_declined
        - network_error
  - name: surge_pricing
    type: surge_pricing
    config:
      peak_hours:
        - "08:00-10:00"
        - "17:00-19:00"
      surge_multipliers: [1.5, 2.0, 3.0]

Output Formats

OpenAPI Specification

Full OpenAPI 3.1 specification with:

  • All endpoints
  • Request/response schemas
  • Authentication
  • Error responses

Personas

4-5 personas based on roles:

  • Driver personas
  • Rider personas
  • Admin personas
  • Support personas

Lifecycle States

6-10 lifecycle states for main entities:

  • Trip lifecycle
  • Payment lifecycle
  • Driver lifecycle
  • Rider lifecycle

WebSocket Topics

If real-time features are mentioned:

  • Topic names
  • Event types
  • Event schemas

Chaos Profiles

Failure and edge case scenarios:

  • Payment failures
  • Network errors
  • Surge pricing
  • Service outages

CI/CD Templates

GitHub Actions and GitLab CI templates:

  • Test workflows
  • Deployment workflows
  • Integration tests

GraphQL Schema

Optional GraphQL schema:

  • Type definitions
  • Queries
  • Mutations

Typings

Type definitions:

  • TypeScript
  • Go
  • Rust
  • Python

Advanced Features

Versioned Artifacts

Generated artifacts are versioned (v1, v2, etc.) and never mutate existing:

generated/
├── v1/
│   ├── openapi.json
│   ├── personas.yaml
│   └── scenarios.yaml
└── v2/
    ├── openapi.json
    ├── personas.yaml
    └── scenarios.yaml

Deterministic Mode

Honors workspace ai.deterministic_mode setting:

ai:
  deterministic_mode:
    enabled: true
    auto_freeze: true
    freeze_format: yaml

When enabled, AI outputs are frozen to deterministic YAML/JSON.

Seeded Generation (#852)

deterministic_mode freezes AI output after generation. For reproducibility during generation — same prompt in, same spec out, across machines and CI runs — use a sampling seed:

# mockforge.yaml
ai:
  seed: 42          # per-deployment default

or via the environment: MOCKFORGE_AI_SEED=42. A seed set on an individual request overrides both. Resolution order: request > config > MOCKFORGE_AI_SEED.

Provider support:

ProviderSeed support
OpenAInative (seed field)
OpenAI-compatible (vLLM, llama.cpp, LM Studio)usually native
Ollamanative (options.seed)
Anthropicnone — pin temperature: 0 instead; identical prompts are typically stable but not guaranteed byte-identical

Determinism guarantee for CI: with a fixed seed, fixed model version, and fixed temperature, seeded providers return identical output for identical input. The recommended QA workflow is still generate-once, bake-to-fixtures (above / auto_freeze): treat the LLM as an authoring tool and run tests against frozen mocks, so provider-side variance can never reach an assertion.

System Coherence Validation

Ensures all generated components are coherent:

  • Personas match endpoints
  • Lifecycles match entities
  • Scenarios match personas
  • WebSocket topics match real-time features

Configuration

Enable System Generation

# mockforge.yaml
ai_studio:
  system_generation:
    enabled: true
    default_output_formats:
      - openapi
      - personas
      - lifecycles
      - scenarios

Output Format Selection

Selecting specific output formats (for example OpenAPI, personas, lifecycles, GraphQL) is planned; there is no CLI option for it yet.

Best Practices

  1. Be Specific: Detailed descriptions yield better results
  2. Mention Roles: Include user roles (drivers, riders, admins)
  3. Specify Features: Mention real-time, payments, etc.
  4. Review Generated: Always review and refine generated artifacts
  5. Iterate: Generate multiple versions and compare

Real-World Examples

E-Commerce Platform

Input:

E-commerce platform with products, shopping cart, orders, payments, 
inventory management, shipping, and customer reviews.

Generated:

  • 25 REST endpoints
  • 5 personas (customer, admin, vendor, support, reviewer)
  • 8 lifecycle states (order, payment, shipping)
  • WebSocket topics (order_updates, inventory_alerts)
  • Payment failure scenarios
  • Inventory depletion chaos profiles

SaaS Platform

Input:

SaaS platform with users, subscriptions, billing, teams, projects, 
tasks, and real-time collaboration.

Generated:

  • 30 REST endpoints
  • 6 personas (admin, owner, member, viewer, billing_admin, support)
  • 10 lifecycle states (subscription, project, task)
  • WebSocket topics (collaboration_updates, task_updates)
  • Billing failure scenarios
  • Subscription lifecycle chaos profiles

AI Behavioral Simulation Engine

Planned / not yet available. The behavioral simulator and AI Studio panel exist, but the backend API is not mounted yet and there is no mockforge ai behavioral-sim command. This page describes the intended design and is kept for reference; do not rely on it in a released build. Track progress at https://github.com/SaaSy-Solutions/mockforge/issues.

Pillars: [AI]

The AI Behavioral Simulation Engine models users as narrative agents that react to app state, form intentions, respond to errors, and trigger multi-step interactions automatically. MockForge becomes an AI user simulator—not just an API simulator.

Overview

Traditional mocks return static responses. The Behavioral Simulation Engine creates narrative agents that:

  • React to app state (e.g., “cart is empty” → intention: “browse products”)
  • Form intentions (shop, browse, buy, abandon, retry, navigate, search, compare, review)
  • Respond to errors (rage clicking on 500 errors, retry logic, cart abandonment on payment failure)
  • Trigger multi-step interactions automatically
  • Maintain session context across interactions

Key Concepts

Narrative Agents

Agents are AI-powered personas that simulate user behavior:

agent:
  agent_id: "agent-123"
  persona_id: "customer:premium-001"
  current_intention: "shop"
  behavioral_traits:
    patience: 0.7
    risk_tolerance: 0.5
    price_sensitivity: 0.3
  state_awareness:
    cart_empty: true
    last_error: null
    session_duration: 120

Intentions

Agents form intentions based on state:

  • Browse: Explore products/content
  • Shop: Actively looking to purchase
  • Buy: Ready to complete purchase
  • Abandon: Leave due to frustration/error
  • Retry: Retry after error
  • Navigate: Move to different section
  • Search: Search for something
  • Compare: Compare options
  • Review: Review/read content

Behavior Policies

Policies define how agents behave:

  • bargain-hunter: Price-sensitive, compares options
  • power-user: Efficient, knows the system
  • churn-risk: Frustrated, likely to abandon
  • new-user: Exploring, needs guidance

Usage

Create Agent

There is no CLI or HTTP endpoint for creating agents yet. The intended flow creates an agent from an existing persona (for example customer:premium-001) with a behavior policy (for example power-user), or generates a new persona for it.

Simulate Behavior

There is no CLI or HTTP endpoint for running a simulation yet. The intended flow passes an agent, the current app state (for example {"cart_empty": true}), and a trigger event (for example user_landed_on_homepage), and returns the agent’s next intention and actions.

Via UI

  1. Navigate to AI Studio
  2. Select “Behavioral Simulation”
  3. Create or select agent
  4. Set app state
  5. Trigger event
  6. Observe agent behavior

Example Workflows

Example 1: Cart Abandonment

State:

{
  "cart_empty": true,
  "last_action": "viewed_product",
  "session_duration": 300
}

Trigger: user_viewed_product

Agent Behavior:

  • Intention: browse
  • Action: GET /api/products?category=electronics
  • Reasoning: “User is browsing, likely looking for products to add to cart”

Example 2: Payment Failure Response

State:

{
  "cart_total": 99.99,
  "payment_attempts": 1,
  "last_error": "payment_failed"
}

Trigger: payment_failed

Agent Behavior:

  • Intention: retry
  • Action: POST /api/payments/retry
  • Reasoning: “User will retry payment once, then abandon if it fails again”

Example 3: Error Rage Clicking

State:

{
  "error_count": 3,
  "last_error": "500",
  "session_duration": 60
}

Trigger: error_occurred

Agent Behavior:

  • Intention: abandon
  • Action: navigate_away
  • Reasoning: “Multiple errors frustrate user, likely to abandon”

Behavior Policies

Bargain Hunter

behavior_policy: bargain-hunter
traits:
  price_sensitivity: 0.9
  comparison_tendency: 0.8
  patience: 0.6
behaviors:
  - always_compares_prices
  - waits_for_discounts
  - abandons_on_high_price

Power User

behavior_policy: power-user
traits:
  efficiency: 0.9
  system_knowledge: 0.8
  patience: 0.7
behaviors:
  - uses_shortcuts
  - expects_fast_responses
  - retries_on_errors

Churn Risk

behavior_policy: churn-risk
traits:
  frustration: 0.8
  patience: 0.3
  loyalty: 0.4
behaviors:
  - abandons_on_errors
  - sensitive_to_latency
  - likely_to_churn

Integration with Personas

Agents can be attached to existing Smart Personas:

persona:
  id: customer:premium-001
  traits:
    subscription_tier: premium
    spending_level: high
  behavioral_simulation:
    enabled: true
    policy: power-user

Configuration

Enable Behavioral Simulation

# mockforge.yaml
ai_studio:
  behavioral_simulation:
    enabled: true
    default_policy: power-user
    llm:
      provider: openai
      model: gpt-4
      temperature: 0.7

Best Practices

  1. Start with Policies: Use pre-built policies before creating custom
  2. Test Scenarios: Test agents with various app states
  3. Monitor Behavior: Track agent behavior patterns
  4. Refine Policies: Adjust policies based on observed behavior
  5. Combine with Personas: Use Smart Personas for realistic agents

Getting Started with SMTP

MockForge includes a fully functional SMTP (Simple Mail Transfer Protocol) server for testing email workflows in your applications. This guide will help you get started quickly.

Quick Start

1. Enable SMTP in Configuration

Create a configuration file or modify your existing config.yaml:

smtp:
  enabled: true
  port: 1025
  host: "0.0.0.0"
  hostname: "mockforge-smtp"

2. Start the Server

mockforge serve --config config.yaml

You should see:

📧 SMTP server listening on localhost:1025

3. Send a Test Email

Using Python’s built-in smtplib:

import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg['Subject'] = 'Test Email'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg.set_content('This is a test email from Python.')

with smtplib.SMTP('localhost', 1025) as server:
    server.send_message(msg)
    print("Email sent successfully!")

4. Verify Email Reception

Currently, emails are stored in the in-memory mailbox. You can verify by checking the server logs or using the API endpoints (if UI is enabled).

Using Command-Line Tools

telnet

telnet localhost 1025
> EHLO client.example.com
> MAIL FROM:<[email protected]>
> RCPT TO:<[email protected]>
> DATA
> Subject: Test Email
>
> This is a test email.
> .
> QUIT

swaks (SMTP Testing Tool)

swaks is a powerful SMTP testing tool:

# Install swaks
# On Ubuntu/Debian: apt install swaks
# On macOS: brew install swaks

# Send test email
swaks --to [email protected] \
      --from [email protected] \
      --server localhost:1025 \
      --body "Test email from swaks" \
      --header "Subject: Test"

Supported SMTP Commands

MockForge SMTP server implements RFC 5321 and supports:

  • HELO / EHLO - Client introduction
  • MAIL FROM - Specify sender
  • RCPT TO - Specify recipient(s)
  • DATA - Send message content
  • RSET - Reset session
  • NOOP - No operation (keepalive)
  • QUIT - End session
  • HELP - List supported commands

Basic Configuration Options

smtp:
  enabled: true               # Enable/disable SMTP server
  port: 1025                  # Port (1025 for dev, 25 for prod)
  host: "0.0.0.0"             # Bind address
  hostname: "mockforge-smtp"  # Server hostname in greeting

  # Mailbox settings
  enable_mailbox: true
  max_mailbox_messages: 1000

  # Timeouts
  timeout_secs: 300
  max_connections: 100

Environment Variables

Override configuration with environment variables:

export MOCKFORGE_SMTP_ENABLED=true
export MOCKFORGE_SMTP_PORT=1025
export MOCKFORGE_SMTP_HOST=0.0.0.0
export MOCKFORGE_SMTP_HOSTNAME=my-smtp-server

mockforge serve

Next Steps

Troubleshooting

Connection Refused

Problem: Cannot connect to SMTP server

Solutions:

  1. Verify SMTP is enabled: smtp.enabled: true
  2. Check the port isn’t in use: lsof -i :1025
  3. Ensure server is running: Look for “SMTP server listening” in logs

Email Not Received

Problem: Email sent but not stored

Solutions:

  1. Check mailbox is enabled: smtp.enable_mailbox: true
  2. Verify mailbox size limit: smtp.max_mailbox_messages
  3. Check server logs for errors

Permission Denied on Port 25

Problem: Cannot bind to port 25

Solution: Ports below 1024 require root privileges. Use port 1025 for development or run with sudo for production testing.

Common Use Cases

Testing Email Workflows

# In your test suite
def test_user_registration_sends_welcome_email():
    # Register user (triggers email send)
    response = client.post('/register', json={
        'email': '[email protected]',
        'password': 'secret'
    })

    assert response.status_code == 201

    # Verify email was sent to MockForge SMTP
    emails = get_emails_from_mockforge()
    assert len(emails) == 1
    assert emails[0]['to'] == '[email protected]'
    assert 'Welcome' in emails[0]['subject']

CI/CD Integration

# .github/workflows/test.yml
- name: Start MockForge SMTP
  run: |
    mockforge serve --smtp --smtp-port 1025 &
    sleep 2

- name: Run tests
  env:
    SMTP_HOST: localhost
    SMTP_PORT: 1025
  run: pytest tests/

What’s Next?

Now that you have a basic SMTP server running, explore:

  1. Fixtures - Define email acceptance rules and auto-replies
  2. Configuration - Fine-tune server behavior
  3. Examples - See real-world implementations

SMTP Configuration Reference

This page provides comprehensive documentation for all SMTP configuration options in MockForge.

Configuration File

Configuration can be provided via YAML or JSON files:

# config.yaml
smtp:
  # Server settings
  enabled: true
  port: 1025
  host: "0.0.0.0"
  hostname: "mockforge-smtp"

  # Connection settings
  timeout_secs: 300
  max_connections: 100

  # Mailbox settings
  enable_mailbox: true
  max_mailbox_messages: 1000

  # Fixtures
  fixtures_dir: "./fixtures/smtp"

Configuration Options

Server Settings

enabled

  • Type: boolean
  • Default: false
  • Description: Enable or disable the SMTP server
smtp:
  enabled: true

port

  • Type: integer
  • Default: 1025
  • Description: Port number for the SMTP server to listen on
  • Notes:
    • Standard SMTP port is 25, but requires root/admin privileges
    • Common development ports: 1025, 2525, 5025
    • Must be between 1 and 65535
smtp:
  port: 1025

host

  • Type: string
  • Default: "0.0.0.0"
  • Description: IP address to bind the server to
  • Options:
    • "0.0.0.0" - Listen on all interfaces
    • "127.0.0.1" - Listen only on localhost
    • Specific IP for network interface
smtp:
  host: "127.0.0.1"  # Localhost only

hostname

  • Type: string
  • Default: "mockforge-smtp"
  • Description: Server hostname used in SMTP greeting and responses
  • Notes: Appears in 220 greeting and 250 HELO/EHLO responses
smtp:
  hostname: "mail.example.com"

Connection Settings

timeout_secs

  • Type: integer
  • Default: 300 (5 minutes — matches the SMTP RFC 5321 recommendation)
  • Description: Connection timeout in seconds
  • Range: 1 to 3600 (1 second to 1 hour)
smtp:
  timeout_secs: 60  # 1 minute timeout

max_connections

  • Type: integer
  • Default: 100
  • Description: Maximum number of concurrent SMTP connections
  • Notes: Prevents resource exhaustion from too many connections
smtp:
  max_connections: 500

Mailbox Settings

enable_mailbox

  • Type: boolean
  • Default: true
  • Description: Enable in-memory mailbox for storing received emails
smtp:
  enable_mailbox: true

max_mailbox_messages

  • Type: integer
  • Default: 1000
  • Description: Maximum number of emails to store in mailbox
  • Notes:
    • Uses FIFO (First In, First Out) when limit is reached
    • Oldest emails are removed when limit is exceeded
    • Set to 0 for unlimited (not recommended)
smtp:
  max_mailbox_messages: 5000

Fixture Settings

fixtures_dir

  • Type: string (path)
  • Default: null (no fixtures)
  • Description: Directory containing SMTP fixture files
  • Notes:
    • Can be absolute or relative path
    • All .yaml and .yml files in directory will be loaded
    • See Fixtures documentation for format
smtp:
  fixtures_dir: "./fixtures/smtp"

Or with absolute path:

smtp:
  fixtures_dir: "/opt/mockforge/fixtures/smtp"

Environment Variables

All configuration options can be overridden with environment variables using the prefix MOCKFORGE_SMTP_:

Environment VariableConfig OptionExample
MOCKFORGE_SMTP_ENABLEDenabledtrue
MOCKFORGE_SMTP_PORTport2525
MOCKFORGE_SMTP_HOSThost127.0.0.1
MOCKFORGE_SMTP_HOSTNAMEhostnametestmail.local

Example

export MOCKFORGE_SMTP_ENABLED=true
export MOCKFORGE_SMTP_PORT=2525
export MOCKFORGE_SMTP_HOST=0.0.0.0
export MOCKFORGE_SMTP_HOSTNAME=test-server

mockforge serve

Command-Line Arguments

Override configuration via CLI arguments:

mockforge serve \
  --smtp-port 2525 \
  --config ./config.yaml

Priority Order

Configuration is applied in the following order (highest to lowest priority):

  1. Command-line arguments
  2. Environment variables
  3. Configuration file
  4. Default values

Complete Example

Development Configuration

# config.dev.yaml
smtp:
  enabled: true
  port: 1025
  host: "127.0.0.1"
  hostname: "dev-smtp"
  timeout_secs: 300
  max_connections: 50
  enable_mailbox: true
  max_mailbox_messages: 500
  fixtures_dir: "./fixtures/smtp"

Production-Like Configuration

# config.prod.yaml
smtp:
  enabled: true
  port: 2525
  host: "0.0.0.0"
  hostname: "mockforge.example.com"
  timeout_secs: 60
  max_connections: 1000
  enable_mailbox: true
  max_mailbox_messages: 10000
  fixtures_dir: "/opt/mockforge/smtp-fixtures"

CI/CD Configuration

# config.ci.yaml
smtp:
  enabled: true
  port: 1025
  host: "127.0.0.1"
  hostname: "ci-smtp"
  timeout_secs: 10
  max_connections: 10
  enable_mailbox: true
  max_mailbox_messages: 100
  fixtures_dir: "./test/fixtures/smtp"

Performance Tuning

High-Volume Scenarios

For testing high-volume email sending:

smtp:
  max_connections: 2000
  max_mailbox_messages: 50000
  timeout_secs: 120

Memory considerations: Each stored email uses approximately 1-5 KB of memory depending on size. 50,000 emails ≈ 50-250 MB.

Low-Resource Environments

For constrained environments (CI, containers):

smtp:
  max_connections: 25
  max_mailbox_messages: 100
  timeout_secs: 15

Best Practices

Security

  1. Bind to localhost in development:

    host: "127.0.0.1"
    
  2. Use non-privileged ports:

    port: 1025  # Not 25
    
  3. Limit connections:

    max_connections: 100
    

Testing

  1. Use fixtures for deterministic tests:

    fixtures_dir: "./fixtures/smtp"
    
  2. Configure appropriate mailbox size:

    max_mailbox_messages: 1000  # Adjust based on test suite
    
  3. Set realistic timeouts:

    timeout_secs: 300  # 5-minute SMTP RFC default, not too long
    

CI/CD

  1. Use environment variables for flexibility:

    MOCKFORGE_SMTP_PORT=1025
    
  2. Start server in background:

    mockforge serve --smtp-port 1025 &
    
  3. Use localhost binding for security:

    host: "127.0.0.1"
    

Troubleshooting

Port Already in Use

Error: Address already in use

Solution:

# Check what's using the port
lsof -i :1025

# Use a different port
mockforge serve --smtp-port 2525

Too Many Open Files

Error: Too many open files

Solution: Reduce max_connections:

smtp:
  max_connections: 50

Out of Memory

Error: OOM or slowdown with large mailbox

Solution: Reduce max_mailbox_messages:

smtp:
  max_mailbox_messages: 1000

SMTP Fixtures

SMTP fixtures allow you to define email acceptance rules, auto-reply behavior, and storage options based on pattern matching. This enables sophisticated email testing scenarios.

Fixture Format

Fixtures are defined in YAML format:

identifier: "welcome-email"
name: "Welcome Email Handler"
description: "Handles welcome emails to new users"

match_criteria:
  recipient_pattern: "^welcome@example\\.com$"
  sender_pattern: null
  subject_pattern: null
  match_all: false

response:
  status_code: 250
  message: "Message accepted"
  delay_ms: 0

auto_reply:
  enabled: false

storage:
  save_to_mailbox: true
  export_to_file: null

behavior:
  failure_rate: 0.0
  delay_ms: 0

Match Criteria

recipient_pattern

  • Type: string (regex) or null
  • Description: Regular expression to match recipient email address
  • Examples:
    • ^user@example\.com$ - Exact match
    • ^.*@example\.com$ - Any user at domain
    • ^admin.*@.*\.com$ - Admin users at any .com domain
match_criteria:
  recipient_pattern: "^support@example\\.com$"

sender_pattern

  • Type: string (regex) or null
  • Description: Regular expression to match sender email address
match_criteria:
  sender_pattern: "^no-reply@.*\\.com$"

subject_pattern

  • Type: string (regex) or null
  • Description: Regular expression to match email subject line
match_criteria:
  subject_pattern: "^\\[URGENT\\].*"

match_all

  • Type: boolean
  • Default: false
  • Description: When true, this fixture matches all emails (catch-all)
match_criteria:
  match_all: true  # Catch-all fixture

Matching Logic

Patterns are evaluated in order:

  1. If match_all is true, fixture matches
  2. Otherwise, all non-null patterns must match:
    • If recipient_pattern is set, it must match
    • If sender_pattern is set, it must match
    • If subject_pattern is set, it must match

Response Configuration

status_code

  • Type: integer
  • Default: 250
  • Description: SMTP status code to return
  • Common codes:
    • 250 - OK (success)
    • 550 - Mailbox unavailable (rejection)
    • 451 - Temporary failure
    • 452 - Insufficient storage
response:
  status_code: 550  # Reject email

message

  • Type: string
  • Description: Response message text
response:
  status_code: 250
  message: "Message accepted for delivery"

delay_ms

  • Type: integer
  • Default: 0
  • Description: Artificial delay before responding (milliseconds)
  • Use case: Simulate slow mail servers
response:
  delay_ms: 500  # 500ms delay

Auto-Reply

Auto-replies allow MockForge to automatically send response emails.

Basic Auto-Reply

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"  # Reply to sender
  subject: "Re: {{subject}}"
  body: |
    Thank you for your email.

    This is an automated response.

Template Variables

Use template variables in auto-reply fields:

  • {{from}} - Original sender email
  • {{to}} - Original recipient email
  • {{subject}} - Original subject
  • {{from_name}} - Extracted name from sender
  • {{now}} - Current timestamp
  • Faker functions: {{faker.name}}, {{faker.email}}, etc.

Example: Welcome Email Auto-Reply

identifier: "welcome-autoresponder"
name: "Welcome Email Auto-Reply"

match_criteria:
  recipient_pattern: "^register@example\\.com$"

response:
  status_code: 250
  message: "Message accepted"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Welcome to Example.com!"
  body: |
    Hi {{from_name}},

    Thank you for registering at Example.com!

    Your registration was received at {{now}}.

    If you have any questions, reply to this email.

    Best regards,
    The Example.com Team

Storage Configuration

save_to_mailbox

  • Type: boolean
  • Default: true
  • Description: Store received email in in-memory mailbox
storage:
  save_to_mailbox: true

export_to_file

  • Type: string (path) or null
  • Description: Export email to file on disk
  • Format: Emails are saved as .eml files
storage:
  save_to_mailbox: true
  export_to_file: "./emails/received"

File naming pattern: {timestamp}_{from}_{to}.eml

Example: [email protected][email protected]

Behavior Configuration

failure_rate

  • Type: float (0.0 to 1.0)
  • Default: 0.0
  • Description: Probability of simulated failure (for testing error handling)
  • Examples:
    • 0.0 - Never fail
    • 0.1 - 10% failure rate
    • 1.0 - Always fail
behavior:
  failure_rate: 0.05  # 5% of emails fail

delay_ms

  • Type: integer
  • Default: 0
  • Description: Artificial delay before processing (milliseconds)
behavior:
  delay_ms: 1000  # 1 second delay

Complete Examples

Example 1: User Registration Emails

identifier: "user-registration"
name: "User Registration Handler"
description: "Handles new user registration confirmation emails"

match_criteria:
  recipient_pattern: "^[^@]+@example\\.com$"
  subject_pattern: "^Registration Confirmation"

response:
  status_code: 250
  message: "Registration email accepted"
  delay_ms: 0

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Welcome! Please Confirm Your Email"
  body: |
    Hello,

    Thank you for registering!

    Please click the link below to confirm your email:
    https://example.com/confirm?token={{uuid}}

    This link expires in 24 hours.

    Best regards,
    Example.com Team

storage:
  save_to_mailbox: true
  export_to_file: "./logs/registration-emails"

behavior:
  failure_rate: 0.0
  delay_ms: 0

Example 2: Support Ticket System

identifier: "support-tickets"
name: "Support Ticket Handler"
description: "Auto-responds to support emails"

match_criteria:
  recipient_pattern: "^support@example\\.com$"

response:
  status_code: 250
  message: "Support ticket created"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Ticket Created: {{subject}}"
  body: |
    Your support ticket has been created.

    Ticket ID: {{uuid}}
    Subject: {{subject}}
    Created: {{now}}

    We'll respond within 24 hours.

    Support Team

storage:
  save_to_mailbox: true

Example 3: Bounced Email Simulation

identifier: "bounce-simulation"
name: "Simulate Bounced Emails"
description: "Rejects emails to invalid addresses"

match_criteria:
  recipient_pattern: "^bounce-test@example\\.com$"

response:
  status_code: 550
  message: "Mailbox unavailable"
  delay_ms: 0

auto_reply:
  enabled: false

storage:
  save_to_mailbox: false

behavior:
  failure_rate: 1.0  # Always fail

Example 4: Slow Server Simulation

identifier: "slow-server"
name: "Slow SMTP Server"
description: "Simulates slow mail server response"

match_criteria:
  recipient_pattern: "^slowtest@example\\.com$"

response:
  status_code: 250
  message: "OK"
  delay_ms: 5000  # 5 second delay

storage:
  save_to_mailbox: true

behavior:
  delay_ms: 3000  # Additional 3 second processing delay

Example 5: Catch-All Default

identifier: "default-handler"
name: "Default Email Handler"
description: "Accepts all emails not matched by other fixtures"

match_criteria:
  match_all: true

response:
  status_code: 250
  message: "Message accepted"

auto_reply:
  enabled: false

storage:
  save_to_mailbox: true

behavior:
  failure_rate: 0.0
  delay_ms: 0

Loading Fixtures

Directory Structure

fixtures/smtp/
├── welcome-email.yaml
├── support-tickets.yaml
├── bounce-simulation.yaml
└── default.yaml

Configuration

smtp:
  fixtures_dir: "./fixtures/smtp"

Fixture Priority

Fixtures are evaluated in alphabetical order by filename. First match wins (except match_all).

To control priority, use numbered prefixes:

fixtures/smtp/
├── 01-bounce.yaml       # Highest priority
├── 02-welcome.yaml
├── 03-support.yaml
└── 99-default.yaml      # Lowest priority (catch-all)

Testing Fixtures

1. Validate Fixture Syntax

# Future command (not yet implemented)
mockforge smtp fixtures validate ./fixtures/smtp/welcome.yaml

2. Test Fixture Matching

Send test email:

swaks --to [email protected] \
      --from [email protected] \
      --server localhost:1025 \
      --header "Subject: Test"

Check server logs for fixture match:

[INFO] Matched fixture: welcome-email

3. Verify Auto-Reply

Check mailbox or export directory for auto-reply email.

Best Practices

1. Specific Before General

Place specific fixtures before general catch-all fixtures:

01-specific-user.yaml
02-domain-specific.yaml
99-catch-all.yaml

2. Use Descriptive Identifiers

identifier: "welcome-new-users"  # Good
identifier: "fixture1"            # Bad

3. Document with Descriptions

description: "Handles password reset emails with confirmation link"

4. Test Failure Scenarios

behavior:
  failure_rate: 0.01  # Test with 1% failure

5. Limit Auto-Replies

Don’t create auto-reply loops:

  • Avoid auto-replying to noreply@ addresses
  • Check sender before replying

Troubleshooting

Fixture Not Matching

  1. Check pattern syntax: Use regex tester (regex101.com)
  2. Check fixture order: Earlier fixtures may match first
  3. Enable debug logging: See which fixture matched
  4. Test with simple pattern: Start with ^.*@example\.com$

Auto-Reply Not Sending

  1. Verify enabled: auto_reply.enabled: true
  2. Check template syntax: Ensure valid template variables
  3. Check logs: Look for auto-reply errors

Performance Issues

  1. Simplify regex: Complex patterns slow matching
  2. Reduce fixtures: Too many fixtures slow evaluation
  3. Disable storage: Set save_to_mailbox: false if not needed

SMTP Examples

This page provides real-world examples of using MockForge SMTP for testing email workflows.

Table of Contents

Testing User Registration

Scenario

Test that your application sends a welcome email when users register.

Fixture

fixtures/smtp/welcome-email.yaml:

identifier: "welcome-email"
name: "Welcome Email"
description: "Auto-responds to new user registration"

match_criteria:
  recipient_pattern: "^[^@]+@example\\.com$"
  subject_pattern: "^Welcome"

response:
  status_code: 250
  message: "Message accepted"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Welcome to Our Platform!"
  body: |
    Hi there!

    Thank you for registering at our platform.

    Click here to verify your email:
    https://example.com/verify?token={{uuid}}

    Best regards,
    The Team

storage:
  save_to_mailbox: true

Python Test

import smtplib
import requests
from email.message import EmailMessage

def test_user_registration_sends_welcome_email():
    # Register a new user
    response = requests.post('http://localhost:8080/api/register', json={
        'email': '[email protected]',
        'password': 'SecurePass123',
        'name': 'Test User'
    })

    assert response.status_code == 201

    # Verify email was sent
    # (In real scenario, you'd query MockForge's mailbox API)
    # For now, manually check logs or implement mailbox checking

def send_test_email():
    """Helper to test fixture directly"""
    msg = EmailMessage()
    msg['Subject'] = 'Welcome to Our Platform'
    msg['From'] = '[email protected]'
    msg['To'] = '[email protected]'
    msg.set_content('Welcome!')

    with smtplib.SMTP('localhost', 1025) as server:
        server.send_message(msg)
        print("Test email sent!")

if __name__ == "__main__":
    send_test_email()

Node.js Test

const nodemailer = require('nodemailer');
const axios = require('axios');
const assert = require('assert');

describe('User Registration', () => {
  it('should send welcome email', async () => {
    // Configure nodemailer to use MockForge
    const transporter = nodemailer.createTransport({
      host: 'localhost',
      port: 1025,
      secure: false,
    });

    // Register user
    const response = await axios.post('http://localhost:8080/api/register', {
      email: '[email protected]',
      password: 'SecurePass123',
      name: 'Test User'
    });

    assert.strictEqual(response.status, 201);

    // Send test email
    await transporter.sendMail({
      from: '[email protected]',
      to: '[email protected]',
      subject: 'Welcome to Our Platform',
      text: 'Welcome!',
    });

    // In production, query MockForge mailbox API here
  });
});

Password Reset Flow

Scenario

Test password reset email with temporary token.

Fixture

fixtures/smtp/password-reset.yaml:

identifier: "password-reset"
name: "Password Reset"

match_criteria:
  recipient_pattern: "^.*@.*$"
  subject_pattern: "^Password Reset"

response:
  status_code: 250
  message: "Reset email accepted"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Password Reset Instructions"
  body: |
    Hello,

    You requested a password reset.

    Click the link below to reset your password:
    https://example.com/reset?token={{uuid}}

    This link expires in 1 hour.

    If you didn't request this, please ignore this email.

    Security Team

storage:
  save_to_mailbox: true
  export_to_file: "./logs/password-resets"

Python Test

import pytest
import smtplib
from email.message import EmailMessage

def trigger_password_reset(email):
    """Trigger password reset in your application"""
    import requests
    response = requests.post('http://localhost:8080/api/password-reset',
                            json={'email': email})
    return response.status_code == 200

def test_password_reset_email():
    email = '[email protected]'

    # Trigger reset
    assert trigger_password_reset(email)

    # Verify email sent (check mailbox)
    # TODO: Implement mailbox API check

def test_password_reset_invalid_email():
    """Test that invalid email is rejected"""
    email = '[email protected]'  # Configured to fail

    # This should fail
    assert not trigger_password_reset(email)

Email Verification

Scenario

Test email verification link generation and sending.

Fixture

fixtures/smtp/email-verification.yaml:

identifier: "email-verification"
name: "Email Verification"

match_criteria:
  subject_pattern: "^Verify Your Email"

response:
  status_code: 250
  message: "Verification email sent"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Verify Your Email Address"
  body: |
    Please verify your email address by clicking below:

    https://example.com/verify?email={{to}}&code={{faker.alphanumeric 32}}

    This link expires in 24 hours.

storage:
  save_to_mailbox: true

Go Test

package main

import (
    "net/smtp"
    "testing"
)

func TestEmailVerification(t *testing.T) {
    // Setup
    smtpHost := "localhost:1025"
    from := "[email protected]"
    to := []string{"[email protected]"}

    // Create message
    message := []byte(
        "Subject: Verify Your Email\r\n" +
        "\r\n" +
        "Please verify your email.\r\n",
    )

    // Send email
    err := smtp.SendMail(smtpHost, nil, from, to, message)
    if err != nil {
        t.Fatalf("Failed to send email: %v", err)
    }

    // Verify sent (check mailbox)
    // TODO: Implement mailbox check
}

Newsletter Subscriptions

Scenario

Test newsletter subscription confirmation emails.

Fixture

fixtures/smtp/newsletter.yaml:

identifier: "newsletter-subscription"
name: "Newsletter Subscription"

match_criteria:
  recipient_pattern: "^newsletter@example\\.com$"

response:
  status_code: 250
  message: "Subscription received"

auto_reply:
  enabled: true
  from: "[email protected]"
  to: "{{from}}"
  subject: "Confirm Your Newsletter Subscription"
  body: |
    Thanks for subscribing to our newsletter!

    Click to confirm: https://example.com/newsletter/confirm?email={{from}}

    You'll receive our weekly digest every Monday.

storage:
  save_to_mailbox: true

Ruby Test

require 'mail'
require 'minitest/autorun'

class NewsletterTest < Minitest::Test
  def setup
    Mail.defaults do
      delivery_method :smtp,
        address: "localhost",
        port: 1025
    end
  end

  def test_newsletter_subscription
    email = Mail.new do
      from     '[email protected]'
      to       '[email protected]'
      subject  'Subscribe'
      body     'Please subscribe me'
    end

    email.deliver!

    # Verify subscription email sent
    # TODO: Check MockForge mailbox
  end
end

CI/CD Integration

GitHub Actions

.github/workflows/test.yml:

name: Test Email Workflows

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      mockforge:
        image: mockforge/mockforge:latest
        ports:
          - 1025:1025
        env:
          MOCKFORGE_SMTP_ENABLED: true
          MOCKFORGE_SMTP_PORT: 1025

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install -r requirements.txt

      - name: Run email tests
        env:
          SMTP_HOST: localhost
          SMTP_PORT: 1025
        run: |
          pytest tests/test_emails.py -v

GitLab CI

.gitlab-ci.yml:

test:
  image: python:3.11
  services:
    - name: mockforge/mockforge:latest
      alias: mockforge
  variables:
    MOCKFORGE_SMTP_ENABLED: "true"
    SMTP_HOST: mockforge
    SMTP_PORT: "1025"
  script:
    - pip install -r requirements.txt
    - pytest tests/test_emails.py

Docker Compose

docker-compose.test.yml:

version: '3.8'

services:
  mockforge:
    image: mockforge/mockforge:latest
    ports:
      - "1025:1025"
    environment:
      MOCKFORGE_SMTP_ENABLED: "true"
      MOCKFORGE_SMTP_PORT: 1025
    volumes:
      - ./fixtures:/fixtures

  app:
    build: .
    depends_on:
      - mockforge
    environment:
      SMTP_HOST: mockforge
      SMTP_PORT: 1025
    command: pytest tests/

Load Testing

Scenario

Test application performance with high email volume.

Python Load Test

import concurrent.futures
import smtplib
from email.message import EmailMessage
import time

def send_email(index):
    """Send a single email"""
    msg = EmailMessage()
    msg['Subject'] = f'Load Test Email {index}'
    msg['From'] = f'loadtest{index}@test.com'
    msg['To'] = '[email protected]'
    msg.set_content(f'This is load test email #{index}')

    try:
        with smtplib.SMTP('localhost', 1025, timeout=5) as server:
            server.send_message(msg)
        return True
    except Exception as e:
        print(f"Error sending email {index}: {e}")
        return False

def load_test(num_emails=1000, num_workers=10):
    """Send many emails concurrently"""
    print(f"Starting load test: {num_emails} emails with {num_workers} workers")

    start_time = time.time()

    with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor:
        results = list(executor.map(send_email, range(num_emails)))

    end_time = time.time()
    duration = end_time - start_time

    success_count = sum(results)
    emails_per_second = num_emails / duration

    print(f"\nResults:")
    print(f"  Total emails: {num_emails}")
    print(f"  Successful: {success_count}")
    print(f"  Failed: {num_emails - success_count}")
    print(f"  Duration: {duration:.2f}s")
    print(f"  Throughput: {emails_per_second:.2f} emails/sec")

if __name__ == "__main__":
    load_test(num_emails=1000, num_workers=20)

Configuration for Load Testing

smtp:
  enabled: true
  port: 1025
  host: "0.0.0.0"
  max_connections: 500
  max_mailbox_messages: 10000
  timeout_secs: 60

Multi-Language Applications

Scenario

Test internationalized email content.

Fixture with Template

fixtures/smtp/i18n-welcome.yaml:

identifier: "i18n-welcome"
name: "Internationalized Welcome"

match_criteria:
  recipient_pattern: "^[^@]+@example\\.com$"
  subject_pattern: "^Welcome|Bienvenue|Willkommen"

response:
  status_code: 250
  message: "Message accepted"

auto_reply:
  enabled: false  # Handle in application

storage:
  save_to_mailbox: true

Python Multi-Language Test

import smtplib
from email.message import EmailMessage
from email.mime.text import MIMEText

def send_welcome_email(recipient, language='en'):
    """Send welcome email in specified language"""

    subjects = {
        'en': 'Welcome to Our Platform',
        'fr': 'Bienvenue sur notre plateforme',
        'de': 'Willkommen auf unserer Plattform',
        'es': 'Bienvenido a nuestra plataforma'
    }

    bodies = {
        'en': 'Welcome! Thank you for registering.',
        'fr': 'Bienvenue! Merci de vous être inscrit.',
        'de': 'Willkommen! Danke für Ihre Registrierung.',
        'es': '¡Bienvenido! Gracias por registrarse.'
    }

    msg = EmailMessage()
    msg['Subject'] = subjects.get(language, subjects['en'])
    msg['From'] = '[email protected]'
    msg['To'] = recipient
    msg['Content-Language'] = language
    msg.set_content(bodies.get(language, bodies['en']))

    with smtplib.SMTP('localhost', 1025) as server:
        server.send_message(msg)

def test_multi_language_emails():
    """Test emails in multiple languages"""
    languages = ['en', 'fr', 'de', 'es']

    for lang in languages:
        send_welcome_email(f'user-{lang}@example.com', lang)
        print(f"Sent {lang} email")

if __name__ == "__main__":
    test_multi_language_emails()

Testing Email Bounces

Scenario

Test application handling of bounced emails.

Fixture

fixtures/smtp/bounce-test.yaml:

identifier: "bounce-simulation"
name: "Bounce Simulation"

match_criteria:
  recipient_pattern: "^bounce@example\\.com$"

response:
  status_code: 550
  message: "Mailbox unavailable"

storage:
  save_to_mailbox: false

behavior:
  failure_rate: 1.0  # Always fail

Test

import smtplib
from email.message import EmailMessage

def test_bounce_handling():
    """Test that application handles bounces correctly"""

    msg = EmailMessage()
    msg['Subject'] = 'Test Bounce'
    msg['From'] = '[email protected]'
    msg['To'] = '[email protected]'
    msg.set_content('This should bounce')

    try:
        with smtplib.SMTP('localhost', 1025) as server:
            server.send_message(msg)
        assert False, "Expected SMTPRecipientsRefused"
    except smtplib.SMTPRecipientsRefused as e:
        # Expected behavior
        print(f"Bounce handled correctly: {e}")
        assert '550' in str(e)

Integration with Testing Frameworks

pytest Fixture

import pytest
import smtplib
from email.message import EmailMessage

@pytest.fixture
def smtp_client():
    """Provides SMTP client connected to MockForge"""
    return smtplib.SMTP('localhost', 1025)

@pytest.fixture
def email_factory():
    """Factory for creating test emails"""
    def _create_email(to, subject="Test", body="Test body"):
        msg = EmailMessage()
        msg['Subject'] = subject
        msg['From'] = '[email protected]'
        msg['To'] = to
        msg.set_content(body)
        return msg
    return _create_email

def test_with_fixtures(smtp_client, email_factory):
    """Test using pytest fixtures"""
    email = email_factory('[email protected]', subject='Welcome')
    smtp_client.send_message(email)
    # Verify email sent

unittest Helper

import unittest
import smtplib

class EmailTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        """Set up SMTP connection for all tests"""
        cls.smtp_host = 'localhost'
        cls.smtp_port = 1025

    def send_test_email(self, to, subject, body):
        """Helper method to send test emails"""
        with smtplib.SMTP(self.smtp_host, self.smtp_port) as server:
            # ... send email
            pass

    def test_email_sending(self):
        self.send_test_email('[email protected]', 'Test', 'Body')
        # Verify

Best Practices

  1. Use dedicated fixtures for each test scenario
  2. Clean mailbox between test runs
  3. Test both success and failure scenarios
  4. Verify email content, not just delivery
  5. Use realistic delays in load tests
  6. Test internationalization early
  7. Mock external dependencies completely

Troubleshooting

Emails Not Received

Check:

  1. SMTP server is running
  2. Correct port (1025)
  3. Fixture patterns match
  4. Mailbox not full

Slow Tests

Optimize:

  1. Reduce delay_ms in fixtures
  2. Disable save_to_mailbox if not needed
  3. Use concurrent connections in load tests

Fixture Not Matching

Debug:

  1. Enable debug logging
  2. Simplify regex patterns
  3. Test patterns with regex101.com
  4. Check fixture load order

Getting Started with MQTT

MockForge includes a fully functional MQTT (Message Queuing Telemetry Transport) broker for testing IoT and pub/sub workflows in your applications. This guide will help you get started quickly.

Quick Start

1. Enable MQTT in Configuration

Create a configuration file or modify your existing config.yaml:

mqtt:
  enabled: true
  port: 1883
  host: "0.0.0.0"
  max_connections: 1000
  max_packet_size: 1048576  # 1MB
  keep_alive_secs: 60

2. Start the Server

mockforge serve --config config.yaml

You should see:

📡 MQTT broker listening on localhost:1883

3. Connect and Publish a Test Message

Using the mosquitto command-line tools:

# Install mosquitto clients (Ubuntu/Debian)
sudo apt install mosquitto-clients

# Or on macOS
brew install mosquitto

# Publish a test message
mosquitto_pub -h localhost -p 1883 -t "sensors/temperature" -m "25.5" -q 1

# Subscribe to receive messages
mosquitto_sub -h localhost -p 1883 -t "sensors/temperature" -q 1

4. Verify Message Handling

Messages are processed according to your fixtures configuration. Check server logs for routing information and fixture matching.

Using Command-Line Tools

mosquitto_pub

Publish messages to topics:

# Simple publish
mosquitto_pub -h localhost -p 1883 -t "sensors/temp/room1" -m "23.5"

# With QoS 1 (at least once delivery)
mosquitto_pub -h localhost -p 1883 -t "devices/status" -m "online" -q 1

# With retained message
mosquitto_pub -h localhost -p 1883 -t "config/max_temp" -m "30.0" -r

# JSON payload
mosquitto_pub -h localhost -p 1883 -t "sensors/data" -m '{"temperature": 22.1, "humidity": 65}'

mosquitto_sub

Subscribe to topics:

# Subscribe to specific topic
mosquitto_sub -h localhost -p 1883 -t "sensors/temp/room1"

# Subscribe with wildcards
mosquitto_sub -h localhost -p 1883 -t "sensors/temp/+"
mosquitto_sub -h localhost -p 1883 -t "devices/#"

# Subscribe to all topics (for debugging)
mosquitto_sub -h localhost -p 1883 -t "#"

MQTT CLI Commands

MockForge provides MQTT-specific CLI commands:

# List active topics
mockforge mqtt topics

# List connected clients
mockforge mqtt clients

# Publish a message
mockforge mqtt publish sensors/temperature 25.5 --qos 1

# Subscribe to topics
mockforge mqtt subscribe "sensors/#" --qos 0

Supported MQTT Features

MockForge MQTT broker implements MQTT 3.1.1 and 5.0 specifications with the following features:

Quality of Service (QoS) Levels

  • QoS 0 - At most once delivery (fire and forget)
  • QoS 1 - At least once delivery (acknowledged delivery)
  • QoS 2 - Exactly once delivery (assured delivery)

Topic Management

  • Single-level wildcards (+) - Match one topic level
  • Multi-level wildcards (#) - Match multiple topic levels
  • Retained messages - Store last message per topic
  • Clean sessions - Persistent vs ephemeral subscriptions

Connection Management

  • Keep-alive handling - Automatic client timeout
  • Will messages - Last-will-and-testament
  • Session persistence - Restore subscriptions on reconnect

Basic Configuration Options

mqtt:
  enabled: true              # Enable/disable MQTT broker
  port: 1883                 # Port (1883 for MQTT, 8883 for MQTT over TLS)
  host: "0.0.0.0"            # Bind address
  max_connections: 1000      # Maximum concurrent connections
  max_packet_size: 1048576   # Maximum packet size (1MB)
  keep_alive_secs: 60        # Default keep-alive timeout

  # Advanced options
  max_inflight_messages: 20  # Maximum QoS 1/2 messages in flight
  max_queued_messages: 100   # Maximum queued messages per client

Environment Variables

Override configuration with environment variables:

export MOCKFORGE_MQTT_ENABLED=true
export MOCKFORGE_MQTT_PORT=1883
export MOCKFORGE_MQTT_HOST=0.0.0.0
export # Configure via mqtt.max_connections in YAML; max_connections=1000

mockforge serve

Next Steps

Troubleshooting

Connection Refused

Problem: Cannot connect to MQTT broker

Solutions:

  1. Verify MQTT is enabled: mqtt.enabled: true
  2. Check the port isn’t in use: lsof -i :1883
  3. Ensure server is running: Look for “MQTT broker listening” in logs

Messages Not Received

Problem: Messages published but not received by subscribers

Solutions:

  1. Check topic matching patterns
  2. Verify QoS levels are compatible
  3. Check for retained message conflicts
  4. Review server logs for routing information

Wildcard Issues

Problem: Wildcard subscriptions not working as expected

Solutions:

  1. + matches exactly one level: sensors/+/temperature
  2. # matches multiple levels: devices/#
  3. Wildcards only work in subscriptions, not publications

Common Use Cases

IoT Device Simulation

# Simulate multiple IoT sensors
import paho.mqtt.client as mqtt
import time
import random

def simulate_sensor(sensor_id, topic_prefix):
    client = mqtt.Client(f"sensor_{sensor_id}")
    client.connect("localhost", 1883, 60)

    while True:
        temperature = 20 + random.uniform(-5, 5)
        payload = f'{{"sensor_id": "{sensor_id}", "temperature": {temperature:.1f}}}'

        client.publish(f"{topic_prefix}/temperature", payload, qos=1)
        time.sleep(5)

# Start multiple sensors
for i in range(3):
    simulate_sensor(f"sensor_{i}", f"sensors/room{i}")

Testing MQTT Applications

// In your test suite (Node.js with mqtt.js)
const mqtt = require('mqtt');

describe('Temperature Monitoring', () => {
  let client;

  beforeAll(() => {
    client = mqtt.connect('mqtt://localhost:1883');
  });

  afterAll(() => {
    client.end();
  });

  test('receives temperature updates', (done) => {
    client.subscribe('sensors/temperature/+', { qos: 1 });

    client.on('message', (topic, message) => {
      const data = JSON.parse(message.toString());
      expect(data).toHaveProperty('sensor_id');
      expect(data).toHaveProperty('temperature');
      expect(data.temperature).toBeGreaterThan(-50);
      expect(data.temperature).toBeLessThan(100);
      done();
    });

    // Trigger temperature reading in your app
    // Your app should publish to sensors/temperature/+
  });
});

CI/CD Integration

# .github/workflows/test.yml
- name: Start MockForge MQTT
  run: |
    mockforge serve --mqtt --mqtt-port 1883 &
    sleep 2

- name: Run MQTT tests
  env:
    MQTT_HOST: localhost
    MQTT_PORT: 1883
  run: npm test

What’s Next?

Now that you have a basic MQTT broker running, explore:

  1. Fixtures - Define MQTT message patterns and mock responses
  2. Configuration - Fine-tune broker behavior
  3. Examples - See real-world implementations

MQTT Configuration Reference

This document covers MockForge’s actual MQTT broker configuration surface in v0.3.x. The MQTT implementation supports MQTT 3.1.1 and 5.0 protocol features (publish, subscribe, QoS 0/1/2, retained messages, wildcards), but the configuration surface itself is intentionally narrow — broader concerns (TLS, auth, ACL, rate limiting) are handled at the platform level rather than by per-protocol fields.

Status legend used in this chapter:

  • Implemented (default) — fields under “Configuration” below.
  • Roadmap — TLS-with-cert-paths, authentication / authorization, topic ACLs, JWT/OAuth2, persistent sessions with custom expiry, and per-client message-flow tuning. Not yet wired into MqttConfig.
  • Use the platform alternative — for cross-cutting concerns (rate limiting, max connections, latency injection, fault injection), configure the chaos engine instead. It hooks every protocol on the same listener config surface.

Configuration

The full set of YAML config knobs MqttConfig accepts in v0.3.x:

mqtt:
  enabled: true                    # Start the MQTT broker
  port: 1883                       # Listener port (TCP, plaintext)
  host: "0.0.0.0"                  # Bind address
  max_connections: 1000            # Reject new clients beyond this count
  max_packet_size: 268435456       # 256 MiB — packet-size cap
  keep_alive_secs: 60              # PINGREQ deadline default
  fixtures_dir: "./fixtures/mqtt"  # Optional: directory of MQTT fixture files
  enable_retained_messages: true   # Honor RETAIN flag on PUBLISH
  max_retained_messages: 10000     # Total retained-message cap across all topics

That’s the entire struct. Anything else you find in older docs is roadmap.

CLI flags

mockforge serve --spec api.yaml --mqtt-port 1883

Environment variables

MOCKFORGE_MQTT_ENABLED=true
MOCKFORGE_MQTT_PORT=1883
MOCKFORGE_MQTT_HOST=0.0.0.0
MOCKFORGE_MQTT_FIXTURES_DIR=./fixtures/mqtt

These are the only MQTT-specific env vars currently honored by the config loader. Setting MOCKFORGE_MQTT_TLS_ENABLED / MOCKFORGE_MQTT_AUTH_* won’t error — they’ll just be silently ignored, because the corresponding config fields don’t exist yet.

QoS support

All three QoS levels work and are honored by the broker:

  • QoS 0 — At most once delivery (fire and forget).
  • QoS 1 — At least once delivery (PUBACK roundtrip).
  • QoS 2 — Exactly once delivery (full PUBREC / PUBREL / PUBCOMP).

QoS is a per-message attribute set by publishing clients. Fixtures can also set QoS levels on auto-published messages — see fixtures.md.

Retained messages and wildcards

Both work as defined by the MQTT specification:

  • enable_retained_messages: true (default) makes MockForge honor the RETAIN flag on PUBLISH and replay the latest retained message on each topic to new subscribers.
  • Subscriptions support + (single-level wildcard) and # (multi-level wildcard). A subscription to sensors/+/temperature matches sensors/garage/temperature but not sensors/garage/humidity/inside.
  • Subscriptions to sensors/# match every topic under sensors/.

Cross-cutting concerns

For features the per-protocol config doesn’t expose, use the chaos engine. Examples:

  • Rate limiting: chaos.rate_limit.requests_per_second caps publishes / subscribes per client.
  • Max connections at a finer scope: chaos.traffic_shaping.max_connections applies platform-wide.
  • Latency injection: chaos.latency.fixed_delay_ms adds delay to every protocol response — useful for slow-broker simulations.
  • Fault injection: drop random messages, force disconnects (TCP-level via chaos.fault_injection.connection_error_kind: tcp_reset).

See the chaos engineering chapter for the full surface.

Roadmap (not yet implemented)

These appeared in older drafts of this chapter; they’re tracked but not landed. Configuring them in mqtt: will be silently ignored:

  • TLS with cert / key / CA paths (only the bare tls_enabled field exists on AMQP today; MQTT doesn’t have any TLS fields)
  • Authentication: basic / JWT / OAuth2 (auth_* fields)
  • Topic ACLs (topic_acl block)
  • Persistent sessions with custom expiry (persistent_sessions, session_expiry_secs)
  • Per-client message-flow tuning (max_inflight_messages, max_queued_messages)
  • Worker-thread / socket buffer tuning

If you need any of these in the meantime, raise an issue describing your use case so it can be prioritized.

Configuration Examples

Local development

mqtt:
  enabled: true
  port: 1883
  host: "127.0.0.1"
  max_connections: 100

IoT-style (lots of slow clients)

mqtt:
  enabled: true
  port: 1883
  host: "0.0.0.0"
  max_connections: 5000
  max_packet_size: 524288         # 512 KiB — typical sensor payload
  keep_alive_secs: 300            # 5 min for battery-powered devices
  enable_retained_messages: true
  max_retained_messages: 50000

With chaos for stress testing

mqtt:
  enabled: true
  port: 1883
  max_connections: 1000

observability:
  chaos:
    enabled: true
    latency:
      fixed_delay_ms: 100
    fault_injection:
      enabled: true
      connection_errors: true
      connection_error_probability: 0.01
      connection_error_kind: tcp_close

Troubleshooting

Connection rejected immediately — check max_connections. The broker hard-caps; clients beyond the cap get refused at TCP accept time.

Clients can connect but RETAIN is ignored — confirm enable_retained_messages: true and that max_retained_messages hasn’t been exhausted.

TLS / auth config silently ignored — see the Roadmap section. These fields aren’t wired yet; configure auth at your reverse-proxy / ingress layer for now.

Next Steps

MQTT Fixtures

MQTT fixtures in MockForge define mock responses for MQTT topics. Unlike HTTP fixtures that respond to requests, MQTT fixtures define what messages should be published when clients publish to specific topics.

Basic Fixture Structure

mqtt:
  fixtures:
    - identifier: "temperature-sensor"
      name: "Temperature Sensor Mock"
      topic_pattern: "^sensors/temperature/[^/]+$"
      qos: 1
      retained: false
      response:
        payload:
          sensor_id: "{{topic_param 2}}"
          temperature: "{{faker.float 15.0 35.0}}"
          unit: "celsius"
          timestamp: "{{now}}"
      auto_publish:
        enabled: false
        interval_ms: 1000
        count: 10

Topic Patterns

MQTT fixtures use regex patterns to match topics:

# Match specific topic
topic_pattern: "^sensors/temperature/room1$"

# Match topic hierarchy with wildcards
topic_pattern: "^sensors/temperature/[^/]+$"

# Match multiple levels
topic_pattern: "^devices/.+/status$"

# Complex patterns
topic_pattern: "^([^/]+)/([^/]+)/(.+)$"

Response Configuration

Static Responses

response:
  payload:
    status: "online"
    version: "1.2.3"
    uptime: 3600

Dynamic Responses with Templates

response:
  payload:
    sensor_id: "{{topic_param 1}}"
    temperature: "{{faker.float 20.0 30.0}}"
    humidity: "{{faker.float 40.0 80.0}}"
    timestamp: "{{now}}"
    random_id: "{{uuid}}"

Template Variables

MockForge supports extensive templating for MQTT responses:

Topic Parameters

  • {{topic}} - Full topic string
  • {{topic_param N}} - Nth segment of topic (0-indexed)

Random Data

  • {{uuid}} - Random UUID
  • {{faker.float min max}} - Random float between min and max
  • {{faker.int min max}} - Random integer between min and max
  • {{rand.float}} - Random float 0.0-1.0
  • {{rand.int}} - Random integer

Time and Dates

  • {{now}} - Current timestamp (RFC3339)
  • {{now + 1h}} - Future timestamp
  • {{now - 30m}} - Past timestamp

Environment Variables

  • {{env VAR_NAME}} - Environment variable value

Quality of Service (QoS)

# QoS 0 - At most once (fire and forget)
qos: 0

# QoS 1 - At least once (acknowledged)
qos: 1

# QoS 2 - Exactly once (assured)
qos: 2

Retained Messages

# Message is retained on the broker
retained: true

# Message is not retained
retained: false

Auto-Publish Configuration

Automatically publish messages at regular intervals:

auto_publish:
  enabled: true
  interval_ms: 5000    # Publish every 5 seconds
  count: 100          # Publish 100 messages, then stop (optional)

Advanced Fixtures

Conditional Responses

fixtures:
  - identifier: "smart-sensor"
    name: "Smart Temperature Sensor"
    topic_pattern: "^sensors/temp/(.+)$"
    response:
      payload: |
        {
          "sensor_id": "{{topic_param 1}}",
          "temperature": {{faker.float 15.0 35.0}},
          "status": "{{#if (> temperature 30.0)}}critical{{else}}normal{{/if}}",
          "timestamp": "{{now}}"
        }
    conditions:
      - variable: "temperature"
        operator: ">"
        value: 30.0
        response:
          payload:
            sensor_id: "{{topic_param 1}}"
            temperature: "{{temperature}}"
            status: "critical"
            alert: true

Sequence Responses

fixtures:
  - identifier: "sequence-demo"
    name: "Sequence Response Demo"
    topic_pattern: "^demo/sequence$"
    sequence:
      - payload:
          step: 1
          message: "Starting sequence"
      - payload:
          step: 2
          message: "Processing..."
      - payload:
          step: 3
          message: "Complete"
    sequence_reset: "manual"  # auto, manual, time

Error Simulation

fixtures:
  - identifier: "faulty-sensor"
    name: "Faulty Sensor"
    topic_pattern: "^sensors/faulty/(.+)$"
    error_simulation:
      enabled: true
      error_rate: 0.1  # 10% of messages fail
      error_responses:
        - payload:
            error: "Sensor malfunction"
            code: "SENSOR_ERROR"
        - payload:
            error: "Communication timeout"
            code: "TIMEOUT"

Fixture Management

Loading Fixtures

# Load fixtures from file
mockforge mqtt fixtures load ./fixtures/mqtt.yaml

# Load fixtures from directory
mockforge mqtt fixtures load ./fixtures/mqtt/

Auto-Publish Control

# Start auto-publishing for all fixtures
mockforge mqtt fixtures start-auto-publish

# Stop auto-publishing
mockforge mqtt fixtures stop-auto-publish

Auto-publish starts and stops for all loaded fixtures at once; there is no per-fixture CLI control.

Fixture Validation

MockForge validates fixtures on load:

  • Topic pattern syntax - Valid regex patterns
  • Template variables - Available variables and functions
  • QoS levels - Valid QoS values (0, 1, 2)
  • JSON structure - Valid JSON payloads

Examples

IoT Sensor Network

mqtt:
  fixtures:
    - identifier: "temp-sensor-room1"
      name: "Room 1 Temperature Sensor"
      topic_pattern: "^sensors/temperature/room1$"
      qos: 1
      retained: true
      response:
        payload:
          sensor_id: "room1"
          temperature: "{{faker.float 20.0 25.0}}"
          humidity: "{{faker.float 40.0 60.0}}"
          battery_level: "{{faker.float 80.0 100.0}}"
          timestamp: "{{now}}"

    - identifier: "motion-sensor"
      name: "Motion Sensor"
      topic_pattern: "^sensors/motion/(.+)$"
      qos: 0
      retained: false
      response:
        payload:
          sensor_id: "{{topic_param 1}}"
          motion_detected: "{{faker.boolean}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 30000  # Every 30 seconds

Smart Home Devices

mqtt:
  fixtures:
    - identifier: "smart-light"
      name: "Smart Light Controller"
      topic_pattern: "^home/lights/(.+)/command$"
      qos: 1
      response:
        payload:
          device_id: "{{topic_param 1}}"
          command: "ack"
          status: "success"
          timestamp: "{{now}}"

    - identifier: "thermostat"
      name: "Smart Thermostat"
      topic_pattern: "^home/climate/thermostat$"
      qos: 2
      retained: true
      response:
        payload:
          temperature: "{{faker.float 18.0 25.0}}"
          humidity: "{{faker.float 35.0 65.0}}"
          mode: "{{faker.random_element heating cooling auto}}"
          setpoint: "{{faker.float 19.0 23.0}}"
          timestamp: "{{now}}"

Industrial IoT

mqtt:
  fixtures:
    - identifier: "conveyor-belt"
      name: "Conveyor Belt Monitor"
      topic_pattern: "^factory/conveyor/(.+)/status$"
      qos: 1
      retained: true
      response:
        payload:
          conveyor_id: "{{topic_param 1}}"
          status: "{{faker.random_element running stopped maintenance}}"
          speed_rpm: "{{faker.float 50.0 150.0}}"
          temperature: "{{faker.float 25.0 45.0}}"
          vibration: "{{faker.float 0.1 2.0}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 5000

    - identifier: "quality-control"
      name: "Quality Control Station"
      topic_pattern: "^factory/qc/(.+)/result$"
      qos: 2
      response:
        payload:
          station_id: "{{topic_param 1}}"
          product_id: "{{uuid}}"
          quality_score: "{{faker.float 85.0 100.0}}"
          defects_found: "{{faker.int 0 3}}"
          passed: "{{#if (> quality_score 90.0)}}true{{else}}false{{/if}}"
          timestamp: "{{now}}"

Best Practices

Topic Design

  • Use hierarchical topics: building/floor/room/device
  • Include device IDs: sensors/temp/sensor_001
  • Use consistent naming conventions

QoS Selection

  • QoS 0: Sensor data, non-critical updates
  • QoS 1: Important status updates, commands
  • QoS 2: Critical control messages, financial data

Retained Messages

  • Use for current state: device/status, sensor/last_reading
  • Avoid for event data: sensor/trigger, button/press

Auto-Publish

  • Reasonable intervals: 1-60 seconds for sensors
  • Consider battery life for IoT devices
  • Use for simulation, not production data

Next Steps

MQTT Examples

This document provides real-world examples of using MockForge MQTT for testing IoT applications, microservices communication, and pub/sub systems.

IoT Device Simulation

Smart Home System

Scenario: Test a smart home application that controls lights, thermostats, and security sensors.

MockForge Configuration:

mqtt:
  enabled: true
  port: 1883

  fixtures:
    # Smart Lights
    - identifier: "living-room-light"
      name: "Living Room Light"
      topic_pattern: "^home/lights/living_room/command$"
      qos: 1
      response:
        payload:
          device_id: "living_room_light"
          status: "success"
          brightness: "{{faker.int 0 100}}"
          timestamp: "{{now}}"

    - identifier: "kitchen-light"
      name: "Kitchen Light"
      topic_pattern: "^home/lights/kitchen/command$"
      qos: 1
      response:
        payload:
          device_id: "kitchen_light"
          status: "success"
          color_temp: "{{faker.int 2700 6500}}"
          timestamp: "{{now}}"

    # Thermostat
    - identifier: "thermostat"
      name: "Smart Thermostat"
      topic_pattern: "^home/climate/thermostat$"
      qos: 2
      retained: true
      response:
        payload:
          temperature: "{{faker.float 18.0 25.0}}"
          humidity: "{{faker.float 35.0 65.0}}"
          mode: "{{faker.random_element heating cooling auto}}"
          setpoint: "{{faker.float 19.0 23.0}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 30000

    # Motion Sensors
    - identifier: "motion-sensor"
      name: "Motion Sensor"
      topic_pattern: "^home/security/motion/(.+)$"
      qos: 0
      response:
        payload:
          sensor_id: "{{topic_param 1}}"
          motion_detected: "{{faker.boolean}}"
          battery_level: "{{faker.float 70.0 100.0}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 15000

Test Code (Python):

import paho.mqtt.client as mqtt
import json
import time

def test_smart_home_integration():
    client = mqtt.Client("test-client")
    client.connect("localhost", 1883, 60)

    # Test light control
    client.publish("home/lights/living_room/command", json.dumps({
        "action": "turn_on",
        "brightness": 80
    }), qos=1)

    # Subscribe to responses
    responses = []
    def on_message(client, userdata, msg):
        responses.append(json.loads(msg.payload.decode()))

    client.on_message = on_message
    client.subscribe("home/lights/living_room/status")
    client.loop_start()

    # Wait for response
    time.sleep(1)
    client.loop_stop()

    assert len(responses) > 0
    assert responses[0]["device_id"] == "living_room_light"
    assert responses[0]["status"] == "success"

    # Test thermostat reading
    client.subscribe("home/climate/thermostat")
    client.loop_start()
    time.sleep(2)  # Wait for auto-published message
    client.loop_stop()

    # Verify thermostat data
    thermostat_data = None
    for response in responses:
        if "temperature" in response:
            thermostat_data = response
            break

    assert thermostat_data is not None
    assert 18.0 <= thermostat_data["temperature"] <= 25.0
    assert thermostat_data["mode"] in ["heating", "cooling", "auto"]

    client.disconnect()

Industrial IoT Monitoring

Scenario: Test an industrial monitoring system with sensors, actuators, and PLCs.

MockForge Configuration:

mqtt:
  enabled: true
  port: 1883
  max_connections: 100

  fixtures:
    # Temperature Sensors
    - identifier: "temp-sensor-1"
      name: "Temperature Sensor 1"
      topic_pattern: "^factory/sensors/temp/1$"
      qos: 1
      retained: true
      response:
        payload:
          sensor_id: "temp_1"
          temperature: "{{faker.float 20.0 80.0}}"
          unit: "celsius"
          status: "operational"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 5000

    # Pressure Sensors
    - identifier: "pressure-sensor"
      name: "Pressure Sensor"
      topic_pattern: "^factory/sensors/pressure/(.+)$"
      qos: 1
      response:
        payload:
          sensor_id: "{{topic_param 1}}"
          pressure: "{{faker.float 0.5 5.0}}"
          unit: "bar"
          threshold: 3.5
          alert: "{{#if (> pressure 3.5)}}true{{else}}false{{/if}}"
          timestamp: "{{now}}"

    # Conveyor Belt Controller
    - identifier: "conveyor-controller"
      name: "Conveyor Belt Controller"
      topic_pattern: "^factory/actuators/conveyor/(.+)/command$"
      qos: 2
      response:
        payload:
          actuator_id: "{{topic_param 1}}"
          command_ack: true
          status: "executing"
          estimated_completion: "{{now + 5s}}"
          timestamp: "{{now}}"

    # Quality Control Station
    - identifier: "qc-station"
      name: "Quality Control Station"
      topic_pattern: "^factory/qc/station_(.+)/result$"
      qos: 2
      response:
        payload:
          station_id: "{{topic_param 1}}"
          product_id: "{{uuid}}"
          quality_score: "{{faker.float 85.0 100.0}}"
          defects: "{{faker.int 0 2}}"
          passed: "{{#if (> quality_score 95.0)}}true{{else}}false{{/if}}"
          timestamp: "{{now}}"

Test Code (JavaScript/Node.js):

const mqtt = require('mqtt');

describe('Industrial IoT System', () => {
  let client;

  beforeAll(() => {
    client = mqtt.connect('mqtt://localhost:1883');
  });

  afterAll(() => {
    client.end();
  });

  test('sensor data collection', (done) => {
    const sensorData = [];

    client.subscribe('factory/sensors/temp/1');
    client.subscribe('factory/sensors/pressure/1');

    client.on('message', (topic, message) => {
      const data = JSON.parse(message.toString());
      sensorData.push({ topic, data });

      if (sensorData.length >= 2) {
        // Verify temperature sensor
        const tempSensor = sensorData.find(s => s.topic === 'factory/sensors/temp/1');
        expect(tempSensor.data.temperature).toBeGreaterThanOrEqual(20);
        expect(tempSensor.data.temperature).toBeLessThanOrEqual(80);
        expect(tempSensor.data.unit).toBe('celsius');

        // Verify pressure sensor
        const pressureSensor = sensorData.find(s => s.topic === 'factory/sensors/pressure/1');
        expect(pressureSensor.data.pressure).toBeGreaterThanOrEqual(0.5);
        expect(pressureSensor.data.pressure).toBeLessThanOrEqual(5.0);
        expect(pressureSensor.data.unit).toBe('bar');

        client.unsubscribe(['factory/sensors/temp/1', 'factory/sensors/pressure/1']);
        done();
      }
    });

    // Trigger sensor readings
    client.publish('factory/sensors/temp/1/trigger', 'read');
    client.publish('factory/sensors/pressure/1/trigger', 'read');
  });

  test('actuator control', (done) => {
    client.subscribe('factory/actuators/conveyor/1/status');

    client.on('message', (topic, message) => {
      if (topic === 'factory/actuators/conveyor/1/status') {
        const status = JSON.parse(message.toString());
        expect(status.actuator_id).toBe('1');
        expect(status.command_ack).toBe(true);
        expect(status.status).toBe('executing');

        client.unsubscribe('factory/actuators/conveyor/1/status');
        done();
      }
    });

    // Send control command
    client.publish('factory/actuators/conveyor/1/command', JSON.stringify({
      action: 'start',
      speed: 50
    }), { qos: 2 });
  });

  test('quality control workflow', (done) => {
    client.subscribe('factory/qc/station_1/result');

    client.on('message', (topic, message) => {
      const result = JSON.parse(message.toString());
      expect(result.station_id).toBe('1');
      expect(result.quality_score).toBeGreaterThanOrEqual(85);
      expect(result.quality_score).toBeLessThanOrEqual(100);
      expect(typeof result.defects).toBe('number');
      expect(typeof result.passed).toBe('boolean');

      client.unsubscribe('factory/qc/station_1/result');
      done();
    });

    // Trigger quality check
    client.publish('factory/qc/station_1/check', JSON.stringify({
      product_id: 'PROD-001',
      batch_id: 'BATCH-2024'
    }));
  });
});

Microservices Communication

Event-Driven Architecture

Scenario: Test microservices communicating via MQTT events.

MockForge Configuration:

mqtt:
  enabled: true
  port: 1883

  fixtures:
    # User Service Events
    - identifier: "user-registered"
      name: "User Registration Event"
      topic_pattern: "^events/user/registered$"
      qos: 1
      response:
        payload:
          event_type: "user_registered"
          user_id: "{{uuid}}"
          email: "{{faker.email}}"
          timestamp: "{{now}}"
          source: "user-service"

    # Order Service Events
    - identifier: "order-created"
      name: "Order Created Event"
      topic_pattern: "^events/order/created$"
      qos: 1
      response:
        payload:
          event_type: "order_created"
          order_id: "{{uuid}}"
          user_id: "{{uuid}}"
          amount: "{{faker.float 10.0 500.0}}"
          currency: "USD"
          items: "{{faker.int 1 10}}"
          timestamp: "{{now}}"
          source: "order-service"

    # Payment Service Events
    - identifier: "payment-processed"
      name: "Payment Processed Event"
      topic_pattern: "^events/payment/processed$"
      qos: 2
      response:
        payload:
          event_type: "payment_processed"
          payment_id: "{{uuid}}"
          order_id: "{{uuid}}"
          amount: "{{faker.float 10.0 500.0}}"
          currency: "USD"
          status: "{{faker.random_element completed failed pending}}"
          method: "{{faker.random_element credit_card paypal bank_transfer}}"
          timestamp: "{{now}}"
          source: "payment-service"

    # Notification Service
    - identifier: "email-notification"
      name: "Email Notification"
      topic_pattern: "^commands/notification/email$"
      qos: 1
      response:
        payload:
          command_type: "send_email"
          notification_id: "{{uuid}}"
          recipient: "{{faker.email}}"
          subject: "Order Confirmation"
          template: "order_confirmation"
          status: "queued"
          timestamp: "{{now}}"

Test Code (Go):

package main

import (
    "encoding/json"
    "testing"
    "time"

    mqtt "github.com/eclipse/paho.mqtt.golang"
)

func TestEventDrivenWorkflow(t *testing.T) {
    opts := mqtt.NewClientOptions().AddBroker("tcp://localhost:1883")
    client := mqtt.NewClient(opts)

    if token := client.Connect(); token.Wait() && token.Error() != nil {
        t.Fatalf("Failed to connect: %v", token.Error())
    }
    defer client.Disconnect(250)

    // Test user registration -> order creation -> payment -> notification flow
    events := make(chan map[string]interface{}, 10)

    // Subscribe to all events
    client.Subscribe("events/#", 1, func(client mqtt.Client, msg mqtt.Message) {
        var event map[string]interface{}
        json.Unmarshal(msg.Payload(), &event)
        events <- event
    })

    // Trigger user registration
    userEvent := map[string]interface{}{
        "user_id": "user-123",
        "email": "[email protected]",
    }
    payload, _ := json.Marshal(userEvent)
    client.Publish("events/user/registered", 1, false, payload)

    // Wait for events
    timeout := time.After(5 * time.Second)
    receivedEvents := make(map[string]int)

    for {
        select {
        case event := <-events:
            eventType := event["event_type"].(string)
            receivedEvents[eventType]++

            // Verify event structure
            switch eventType {
            case "user_registered":
                if event["user_id"] == nil || event["email"] == nil {
                    t.Errorf("Invalid user_registered event: %v", event)
                }
            case "order_created":
                if event["order_id"] == nil || event["amount"] == nil {
                    t.Errorf("Invalid order_created event: %v", event)
                }
            case "payment_processed":
                if event["payment_id"] == nil || event["status"] == nil {
                    t.Errorf("Invalid payment_processed event: %v", event)
                }
            }
        case <-timeout:
            // Check that we received expected events
            if receivedEvents["user_registered"] == 0 {
                t.Error("Expected user_registered event")
            }
            if receivedEvents["order_created"] == 0 {
                t.Error("Expected order_created event")
            }
            if receivedEvents["payment_processed"] == 0 {
                t.Error("Expected payment_processed event")
            }
            return
        }
    }
}

Real-Time Data Streaming

Live Dashboard Testing

Scenario: Test a real-time dashboard that displays sensor data and alerts.

MockForge Configuration:

mqtt:
  enabled: true
  port: 1883

  fixtures:
    # Environmental Sensors
    - identifier: "env-sensor-cluster"
      name: "Environmental Sensor Cluster"
      topic_pattern: "^sensors/env/(.+)/(.+)$"
      qos: 0
      response:
        payload:
          sensor_type: "{{topic_param 2}}"
          location: "{{topic_param 1}}"
          value: "{{#switch topic_param.2}}
                     {{#case 'temperature'}}{{faker.float 15.0 35.0}}{{/case}}
                     {{#case 'humidity'}}{{faker.float 30.0 90.0}}{{/case}}
                     {{#case 'co2'}}{{faker.float 400.0 2000.0}}{{/case}}
                     {{#default}}0{{/default}}
                   {{/switch}}"
          unit: "{{#switch topic_param.2}}
                   {{#case 'temperature'}}celsius{{/case}}
                   {{#case 'humidity'}}percent{{/case}}
                   {{#case 'co2'}}ppm{{/case}}
                   {{#default}}unit{{/default}}
                 {{/switch}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 2000

    # System Alerts
    - identifier: "system-alerts"
      name: "System Alerts"
      topic_pattern: "^alerts/system/(.+)$"
      qos: 1
      response:
        payload:
          alert_type: "{{topic_param 1}}"
          severity: "{{faker.random_element info warning error critical}}"
          message: "{{#switch topic_param.1}}
                      {{#case 'temperature'}}High temperature detected{{/case}}
                      {{#case 'power'}}Power supply issue{{/case}}
                      {{#case 'network'}}Network connectivity lost{{/case}}
                      {{#default}}System alert{{/default}}
                    {{/switch}}"
          sensor_id: "{{uuid}}"
          timestamp: "{{now}}"
      auto_publish:
        enabled: true
        interval_ms: 30000

Test Code (Rust):

#![allow(unused)]
fn main() {
use paho_mqtt as mqtt;
use std::time::Duration;

#[tokio::test]
async fn test_realtime_dashboard() {
    let create_opts = mqtt::CreateOptionsBuilder::new()
        .server_uri("tcp://localhost:1883")
        .client_id("dashboard-test")
        .finalize();

    let mut client = mqtt::AsyncClient::new(create_opts).unwrap();
    let conn_opts = mqtt::ConnectOptions::new();
    client.connect(conn_opts).await.unwrap();

    // Subscribe to sensor data
    client.subscribe("sensors/env/+/temperature", mqtt::QOS_0).await.unwrap();
    client.subscribe("sensors/env/+/humidity", mqtt::QOS_0).await.unwrap();
    client.subscribe("alerts/system/+", mqtt::QOS_1).await.unwrap();

    let mut receiver = client.get_stream(100);
    let mut message_count = 0;
    let mut alerts_received = 0;

    // Collect messages for 10 seconds
    let start_time = std::time::Instant::now();
    while start_time.elapsed() < Duration::from_secs(10) {
        if let Ok(Some(msg)) = tokio::time::timeout(Duration::from_millis(100), receiver.recv()).await {
            message_count += 1;

            let payload: serde_json::Value = serde_json::from_str(&msg.payload_str()).unwrap();

            // Verify sensor data structure
            if msg.topic().contains("sensors/env") {
                assert!(payload.get("sensor_type").is_some());
                assert!(payload.get("location").is_some());
                assert!(payload.get("value").is_some());
                assert!(payload.get("unit").is_some());
                assert!(payload.get("timestamp").is_some());
            }

            // Count alerts
            if msg.topic().contains("alerts/system") {
                alerts_received += 1;
                assert!(payload.get("alert_type").is_some());
                assert!(payload.get("severity").is_some());
                assert!(payload.get("message").is_some());
            }
        }
    }

    // Verify we received data
    assert!(message_count > 0, "No messages received");
    assert!(alerts_received > 0, "No alerts received");

    client.disconnect(None).await.unwrap();
}
}

CI/CD Integration

Automated Testing Pipeline

# .github/workflows/mqtt-tests.yml
name: MQTT Integration Tests

on: [push, pull_request]

jobs:
  mqtt-tests:
    runs-on: ubuntu-latest

    services:
      mockforge:
        image: mockforge:latest
        ports:
          - 1883:1883
        env:
          MOCKFORGE_MQTT_ENABLED: true
          MOCKFORGE_MQTT_FIXTURES: ./test-fixtures/mqtt/

    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Wait for MockForge
        run: |
          timeout 30 bash -c 'until nc -z localhost 1883; do sleep 1; done'

      - name: Run MQTT tests
        run: npm test -- --testPathPattern=mqtt
        env:
          MQTT_BROKER: localhost:1883

Performance Testing

Load Testing MQTT Broker

mqtt:
  enabled: true
  port: 1883
  max_connections: 1000

  fixtures:
    - identifier: "load-test-sensor"
      name: "Load Test Sensor"
      topic_pattern: "^loadtest/sensor/(.+)$"
      qos: 0
      response:
        payload:
          sensor_id: "{{topic_param 1}}"
          value: "{{faker.float 0.0 100.0}}"
          timestamp: "{{now}}"

Load Test Script (Python):

import paho.mqtt.client as mqtt
import threading
import time
import json

def create_publisher(client_id, num_messages):
    client = mqtt.Client(f"publisher-{client_id}")
    client.connect("localhost", 1883, 60)

    for i in range(num_messages):
        payload = {
            "sensor_id": f"sensor_{client_id}_{i}",
            "value": i * 1.5,
            "timestamp": time.time()
        }
        client.publish(f"loadtest/sensor/{client_id}", json.dumps(payload), qos=0)

    client.disconnect()

def load_test():
    num_publishers = 50
    messages_per_publisher = 100

    start_time = time.time()

    threads = []
    for i in range(num_publishers):
        thread = threading.Thread(target=create_publisher, args=(i, messages_per_publisher))
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

    end_time = time.time()
    total_messages = num_publishers * messages_per_publisher
    duration = end_time - start_time

    print(f"Published {total_messages} messages in {duration:.2f} seconds")
    print(f"Throughput: {total_messages / duration:.0f} messages/second")

if __name__ == "__main__":
    load_test()

Next Steps

Getting Started with FTP Mocking

MockForge provides comprehensive FTP server mocking capabilities, allowing you to simulate FTP file transfers for testing and development purposes.

Quick Start

Starting an FTP Server

# Start a basic FTP server on port 2121
mockforge ftp serve --port 2121

# Start with custom configuration
mockforge ftp serve --host 0.0.0.0 --port 2121 --virtual-root /mockforge

Connecting with an FTP Client

Once the server is running, you can connect using any FTP client:

# Using lftp
lftp ftp://localhost:2121

# Using curl
curl ftp://localhost:2121/

# Using FileZilla or other GUI clients
# Host: localhost
# Port: 2121
# Username: (leave blank for anonymous)
# Password: (leave blank)

Basic Concepts

Virtual File System

MockForge FTP uses an in-memory virtual file system that supports:

  • Static files: Pre-defined content
  • Template files: Dynamic content generation using Handlebars
  • Generated files: Synthetic content (random, zeros, patterns)
  • Upload handling: Configurable validation and storage rules

File Content Types

Static Content

# Add a static file
mockforge ftp vfs add /hello.txt --content "Hello, World!"

Template Content

# Add a template file with dynamic content
mockforge ftp vfs add /user.json --template '{"name": "{{faker.name}}", "id": "{{uuid}}", "timestamp": "{{now}}"}'

Generated Content

# Add a file with random content
mockforge ftp vfs add /random.bin --generate random --size 1024

# Add a file filled with zeros
mockforge ftp vfs add /zeros.bin --generate zeros --size 1024

FTP Commands Supported

MockForge supports standard FTP commands:

  • LIST - Directory listing
  • RETR - Download files
  • STOR - Upload files
  • DELE - Delete files
  • PWD - Print working directory
  • SIZE - Get file size
  • CWD - Change directory (limited support)

Example Session

$ mockforge ftp serve --port 2121 &
$ lftp localhost:2121
lftp localhost:2121:~> ls
-rw-r--r-- 1 mockforge ftp          0 Jan 01 00:00 test.txt
lftp localhost:2121:~> put localfile.txt
lftp localhost:2121:~> get test.txt
lftp localhost:2121:~> quit

Next Steps

FTP Server Configuration

MockForge FTP servers can be configured through command-line options or configuration files.

Command Line Options

Server Options

mockforge ftp serve [OPTIONS]
OptionDescriptionDefault
--port <PORT>FTP server port2121
--host <HOST>FTP server host0.0.0.0
--virtual-root <PATH>Virtual file system root path/mockforge
--config <FILE>Configuration file path-

Examples

# Basic server
mockforge ftp serve

# Custom port and host
mockforge ftp serve --port 2122 --host 0.0.0.0

# With configuration file
mockforge ftp serve --config ftp-config.yaml

Configuration File

FTP servers can be configured using a YAML configuration file:

ftp:
  host: "127.0.0.1"
  port: 2121
  virtual_root: "/"
  fixtures:
    - name: "sample_files"
      description: "Sample files for testing"
      virtual_files:
        - path: "/welcome.txt"
          content:
            type: "static"
            content: "Welcome to MockForge FTP!"
          permissions: "644"
          owner: "ftp"
          group: "ftp"
      upload_rules:
        - path_pattern: "/uploads/.*"
          auto_accept: true
          max_size_bytes: 1048576  # 1MB
          allowed_extensions: ["txt", "json", "xml"]
          storage:
            type: "memory"

Virtual File System Configuration

File Content Types

Static Content

content:
  type: "static"
  content: "Hello, World!"

Template Content

content:
  type: "template"
  template: '{"user": "{{faker.name}}", "id": "{{uuid}}", "time": "{{now}}"}'

Generated Content

content:
  type: "generated"
  size: 1024
  pattern: "random"  # random, zeros, ones, incremental

Upload Rules

Upload rules control how files are accepted and stored:

upload_rules:
  - path_pattern: "/uploads/.*"  # Regex pattern
    auto_accept: true           # Auto-accept uploads
    max_size_bytes: 1048576     # Maximum file size
    allowed_extensions:         # Allowed file extensions
      - "txt"
      - "json"
    storage:                    # Storage backend
      type: "memory"           # memory, file, discard

Storage Options

Memory Storage

Files are stored in memory (default):

storage:
  type: "memory"

File Storage

Files are written to the local filesystem:

storage:
  type: "file"
  path: "/tmp/uploads"

Discard Storage

Files are accepted but not stored:

storage:
  type: "discard"

Template Variables

When using template content, the following variables are available:

Timestamps

  • {{now}} - Current timestamp in RFC3339 format
  • {{timestamp}} - Unix timestamp (seconds)
  • {{date}} - Current date (YYYY-MM-DD)
  • {{time}} - Current time (HH:MM:SS)

Random Values

  • {{random_int}} - Random 64-bit integer
  • {{random_float}} - Random float (0.0-1.0)
  • {{uuid}} - Random UUID v4

Sample Data

  • {{faker.name}} - Random name
  • {{faker.email}} - Random email address
  • {{faker.age}} - Random age (18-80)

Example Templates

# JSON response with dynamic data
content:
  type: "template"
  template: |
    {
      "id": "{{uuid}}",
      "name": "{{faker.name}}",
      "email": "{{faker.email}}",
      "created_at": "{{now}}",
      "age": {{faker.age}}
    }

# Log file with timestamps
content:
  type: "template"
  template: "[{{timestamp}}] INFO: Application started at {{time}}"

Passive Mode Configuration

FTP passive mode uses dynamic port ranges. The server automatically configures passive ports in the range 49152-65535.

Authentication

Currently, MockForge FTP servers support anonymous access only. Authentication can be added in future versions.

Performance Tuning

Memory Usage

  • Virtual file system stores all files in memory
  • Large files or many files may consume significant memory
  • Consider using file-based storage for large uploads

Connection Limits

FtpConfig::max_connections (default 100) caps concurrent control-channel sessions; new clients beyond that are refused at TCP accept time. Adjust upward for production-like setups; consider system ulimit -n (open file descriptors) as the platform-level ceiling.

ftp:
  max_connections: 500

Timeouts

FtpConfig::timeout_secs (default 300 — 5 minutes) is the per-connection idle timeout. Sessions that go quiet longer than this get closed by the server. Set lower for aggressive cleanup of stuck clients; raise for long-running batch transfers.

ftp:
  timeout_secs: 600     # 10 minutes

FTP Fixtures

FTP fixtures allow you to pre-configure file structures and upload rules for your mock FTP server.

Fixture Structure

Fixtures are defined in YAML format and contain:

  • Virtual files: Pre-defined files in the virtual file system
  • Upload rules: Rules for accepting and handling file uploads

Basic Fixture Example

fixtures:
  - name: "sample_files"
    description: "Sample files for testing FTP clients"
    virtual_files:
      - path: "/welcome.txt"
        content:
          type: "static"
          content: "Welcome to MockForge FTP Server!"
        permissions: "644"
        owner: "ftp"
        group: "ftp"
      - path: "/data.json"
        content:
          type: "template"
          template: '{"timestamp": "{{now}}", "server": "mockforge"}'
        permissions: "644"
        owner: "ftp"
        group: "ftp"
    upload_rules:
      - path_pattern: "/uploads/.*"
        auto_accept: true
        max_size_bytes: 1048576
        allowed_extensions: ["txt", "json", "xml"]
        storage:
          type: "memory"

Virtual Files

Static Content Files

virtual_files:
  - path: "/readme.txt"
    content:
      type: "static"
      content: |
        This is a mock FTP server.
        You can upload files to the /uploads directory.
    permissions: "644"
    owner: "ftp"
    group: "ftp"

Template Files

virtual_files:
  - path: "/status.json"
    content:
      type: "template"
      template: |
        {
          "server": "MockForge FTP",
          "version": "1.0.0",
          "uptime": "{{timestamp}}",
          "status": "running"
        }
    permissions: "644"
    owner: "ftp"
    group: "ftp"

Generated Content Files

virtual_files:
  - path: "/random.bin"
    content:
      type: "generated"
      size: 1024
      pattern: "random"
    permissions: "644"
    owner: "ftp"
    group: "ftp"

Upload Rules

Upload rules control how the server handles file uploads.

Basic Upload Rule

upload_rules:
  - path_pattern: "/uploads/.*"
    auto_accept: true
    storage:
      type: "memory"

Advanced Upload Rule

upload_rules:
  - path_pattern: "/documents/.*"
    auto_accept: true
    validation:
      max_size_bytes: 5242880  # 5MB
      allowed_extensions: ["pdf", "doc", "docx", "txt"]
      mime_types: ["application/pdf", "application/msword"]
    storage:
      type: "file"
      path: "/tmp/uploads"

Validation Options

File Size Limits

validation:
  max_size_bytes: 1048576  # 1MB limit

File Extensions

validation:
  allowed_extensions: ["jpg", "png", "gif"]

MIME Types

validation:
  mime_types: ["image/jpeg", "image/png"]

Storage Backends

Memory Storage

Files are stored in memory (default):

storage:
  type: "memory"

File Storage

Files are written to disk:

storage:
  type: "file"
  path: "/var/ftp/uploads"

Discard Storage

Files are accepted but not stored:

storage:
  type: "discard"

Loading Fixtures

From Configuration File

mockforge ftp serve --config ftp-config.yaml

From Directory

mockforge ftp fixtures load ./fixtures/ftp/

Validate Fixtures

mockforge ftp fixtures validate fixture.yaml

Example Complete Fixture

fixtures:
  - name: "test_environment"
    description: "Complete test environment with various file types"
    virtual_files:
      # Static files
      - path: "/readme.txt"
        content:
          type: "static"
          content: "FTP Test Server - Upload files to /uploads/"
        permissions: "644"
        owner: "ftp"
        group: "ftp"

      # Template files
      - path: "/server-info.json"
        content:
          type: "template"
          template: |
            {
              "server": "MockForge FTP",
              "started_at": "{{now}}",
              "session_id": "{{uuid}}"
            }
        permissions: "644"
        owner: "ftp"
        group: "ftp"

      # Generated files
      - path: "/test-data.bin"
        content:
          type: "generated"
          size: 4096
          pattern: "random"
        permissions: "644"
        owner: "ftp"
        group: "ftp"

    upload_rules:
      # General uploads
      - path_pattern: "/uploads/.*"
        auto_accept: true
        validation:
          max_size_bytes: 10485760  # 10MB
        storage:
          type: "memory"

      # Image uploads
      - path_pattern: "/images/.*"
        auto_accept: true
        validation:
          max_size_bytes: 5242880  # 5MB
          allowed_extensions: ["jpg", "jpeg", "png", "gif"]
          mime_types: ["image/jpeg", "image/png", "image/gif"]
        storage:
          type: "file"
          path: "/tmp/images"

      # Log files (discard)
      - path_pattern: "/logs/.*"
        auto_accept: true
        storage:
          type: "discard"

CLI Management

List Fixtures

mockforge ftp fixtures list

Load Fixtures

# Load from directory
mockforge ftp fixtures load ./fixtures/

# Load specific file
mockforge ftp fixtures load fixture.yaml

Validate Fixtures

mockforge ftp fixtures validate fixture.yaml

Virtual File System Management

Add Files

# Static content
mockforge ftp vfs add /hello.txt --content "Hello World"

# Template content
mockforge ftp vfs add /user.json --template '{"name": "{{faker.name}}"}'

# Generated content
mockforge ftp vfs add /data.bin --generate random --size 1024

List Files

mockforge ftp vfs list /

Remove Files

mockforge ftp vfs remove /old-file.txt

Get File Info

mockforge ftp vfs info /hello.txt

FTP Examples

This section provides complete examples of using MockForge FTP for various testing scenarios.

Basic FTP Server

Starting a Simple Server

# Start FTP server on default port 2121
mockforge ftp serve

# Start on custom port
mockforge ftp serve --port 2122

# Start with custom host
mockforge ftp serve --host 0.0.0.0 --port 2121

Connecting with FTP Clients

Using lftp

# Connect to the server
lftp localhost:2121

# List files
lftp localhost:2121:~> ls

# Download a file
lftp localhost:2121:~> get test.txt

# Upload a file
lftp localhost:2121:~> put localfile.txt

# Exit
lftp localhost:2121:~> quit

Using curl

# List directory
curl ftp://localhost:2121/

# Download file
curl ftp://localhost:2121/test.txt -o downloaded.txt

# Upload file
curl -T localfile.txt ftp://localhost:2121/

Using Python

import ftplib

# Connect to FTP server
ftp = ftplib.FTP('localhost', 'anonymous', '')

# List files
files = ftp.nlst()
print("Files:", files)

# Download file
with open('downloaded.txt', 'wb') as f:
    ftp.retrbinary('RETR test.txt', f.write)

# Upload file
with open('localfile.txt', 'rb') as f:
    ftp.storbinary('STOR uploaded.txt', f)

ftp.quit()

File Management Examples

Adding Static Files

# Add a simple text file
mockforge ftp vfs add /hello.txt --content "Hello, FTP World!"

# Add a JSON file
mockforge ftp vfs add /config.json --content '{"server": "mockforge", "port": 2121}'

# Add a larger file
echo "This is a test file with multiple lines." > test.txt
mockforge ftp vfs add /multiline.txt --content "$(cat test.txt)"

Adding Template Files

# Add a dynamic JSON response
mockforge ftp vfs add /user.json --template '{"id": "{{uuid}}", "name": "{{faker.name}}", "created": "{{now}}"}'

# Add a log file with timestamps
mockforge ftp vfs add /server.log --template '[{{timestamp}}] Server started at {{time}}'

# Add a status file
mockforge ftp vfs add /status.xml --template '<?xml version="1.0"?><status><server>MockForge</server><time>{{now}}</time></status>'

Adding Generated Files

# Add a random binary file (1KB)
mockforge ftp vfs add /random.bin --generate random --size 1024

# Add a file filled with zeros (512 bytes)
mockforge ftp vfs add /zeros.dat --generate zeros --size 512

# Add an incremental pattern file
mockforge ftp vfs add /pattern.bin --generate incremental --size 256

Managing Files

# List all files
mockforge ftp vfs list /

# Get file information
mockforge ftp vfs info /hello.txt

# Remove a file
mockforge ftp vfs remove /old-file.txt

Configuration Examples

Basic Configuration File

# ftp-config.yaml
ftp:
  host: "127.0.0.1"
  port: 2121
  virtual_root: "/"
  fixtures:
    - name: "basic_files"
      description: "Basic test files"
      virtual_files:
        - path: "/readme.txt"
          content:
            type: "static"
            content: "Welcome to MockForge FTP Server"
          permissions: "644"
          owner: "ftp"
          group: "ftp"
      upload_rules:
        - path_pattern: "/uploads/.*"
          auto_accept: true
          storage:
            type: "memory"

Advanced Configuration

# advanced-ftp-config.yaml
ftp:
  host: "0.0.0.0"
  port: 2121
  virtual_root: "/ftp"
  fixtures:
    - name: "api_test_files"
      description: "Files for API testing"
      virtual_files:
        # Static files
        - path: "/api/v1/users"
          content:
            type: "static"
            content: '[{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]'
          permissions: "644"
          owner: "api"
          group: "users"

        # Template files
        - path: "/api/v1/status"
          content:
            type: "template"
            template: '{"status": "ok", "timestamp": "{{now}}", "version": "1.0.0"}'
          permissions: "644"
          owner: "api"
          group: "system"

        # Generated test data
        - path: "/test/data.bin"
          content:
            type: "generated"
            size: 1048576  # 1MB
            pattern: "random"
          permissions: "644"
          owner: "test"
          group: "data"

      upload_rules:
        # General uploads
        - path_pattern: "/uploads/.*"
          auto_accept: true
          validation:
            max_size_bytes: 10485760  # 10MB
          storage:
            type: "memory"

        # Image uploads
        - path_pattern: "/images/.*"
          auto_accept: true
          validation:
            max_size_bytes: 5242880  # 5MB
            allowed_extensions: ["jpg", "png", "gif"]
          storage:
            type: "file"
            path: "/tmp/ftp/images"

        # Log files (accepted but discarded)
        - path_pattern: "/logs/.*"
          auto_accept: true
          storage:
            type: "discard"

Testing Scenarios

File Upload Testing

# Start server with upload configuration
mockforge ftp serve --config upload-config.yaml

# Test file upload with curl
echo "Test file content" > test.txt
curl -T test.txt ftp://localhost:2121/uploads/

# Test large file upload
dd if=/dev/zero of=large.bin bs=1M count=5
curl -T large.bin ftp://localhost:2121/uploads/

# Test invalid file type
echo "invalid content" > invalid.exe
curl -T invalid.exe ftp://localhost:2121/uploads/  # Should fail

Load Testing

# Start server
mockforge ftp serve --port 2121 &

# Simple load test with parallel uploads
for i in {1..10}; do
  echo "File $i content" > "file$i.txt"
  curl -T "file$i.txt" "ftp://localhost:2121/uploads/file$i.txt" &
done
wait

Integration Testing

With pytest

# test_ftp_integration.py
import ftplib
import pytest
import tempfile
import os

class TestFTPIntegration:
    @pytest.fixture(scope="class")
    def ftp_client(self):
        # Connect to MockForge FTP server
        ftp = ftplib.FTP('localhost', 'anonymous', '')
        yield ftp
        ftp.quit()

    def test_list_files(self, ftp_client):
        files = ftp_client.nlst()
        assert len(files) >= 0  # At least empty directory

    def test_download_file(self, ftp_client):
        # Assuming server has a test file
        with tempfile.NamedTemporaryFile(delete=False) as tmp:
            try:
                ftp_client.retrbinary('RETR test.txt', tmp.write)
                assert os.path.getsize(tmp.name) > 0
            finally:
                os.unlink(tmp.name)

    def test_upload_file(self, ftp_client):
        # Create test file
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp:
            tmp.write("Test upload content")
            tmp_path = tmp.name

        try:
            # Upload file
            with open(tmp_path, 'rb') as f:
                ftp_client.storbinary('STOR uploaded.txt', f)

            # Verify upload (if server supports listing uploads)
            files = ftp_client.nlst()
            assert 'uploaded.txt' in [os.path.basename(f) for f in files]
        finally:
            os.unlink(tmp_path)

With Java

// FtpIntegrationTest.java
import org.apache.commons.net.ftp.FTPClient;
import org.junit.jupiter.api.*;
import java.io.*;

class FtpIntegrationTest {
    private FTPClient ftpClient;

    @BeforeEach
    void setup() throws IOException {
        ftpClient = new FTPClient();
        ftpClient.connect("localhost", 2121);
        ftpClient.login("anonymous", "");
        ftpClient.enterLocalPassiveMode();
    }

    @AfterEach
    void teardown() throws IOException {
        if (ftpClient.isConnected()) {
            ftpClient.disconnect();
        }
    }

    @Test
    void testFileDownload() throws IOException {
        // Download a file
        File tempFile = File.createTempFile("downloaded", ".txt");
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            boolean success = ftpClient.retrieveFile("test.txt", fos);
            Assertions.assertTrue(success, "File download should succeed");
            Assertions.assertTrue(tempFile.length() > 0, "Downloaded file should not be empty");
        } finally {
            tempFile.delete();
        }
    }

    @Test
    void testFileUpload() throws IOException {
        // Create test file
        File tempFile = File.createTempFile("upload", ".txt");
        try (FileWriter writer = new FileWriter(tempFile)) {
            writer.write("Test upload content");
        }

        // Upload file
        try (FileInputStream fis = new FileInputStream(tempFile)) {
            boolean success = ftpClient.storeFile("uploaded.txt", fis);
            Assertions.assertTrue(success, "File upload should succeed");
        } finally {
            tempFile.delete();
        }
    }

    @Test
    void testDirectoryListing() throws IOException {
        FTPFile[] files = ftpClient.listFiles();
        Assertions.assertNotNull(files, "Directory listing should not be null");
        // Additional assertions based on expected files
    }
}

Docker Integration

Running in Docker

# Dockerfile
FROM mockforge:latest

# Copy FTP configuration
COPY ftp-config.yaml /app/config/

# Expose FTP port
EXPOSE 2121

# Start FTP server
CMD ["mockforge", "ftp", "serve", "--config", "/app/config/ftp-config.yaml"]
# Build and run
docker build -t mockforge-ftp .
docker run -p 2121:2121 mockforge-ftp

Docker Compose

# docker-compose.yml
version: '3.8'
services:
  ftp-server:
    image: mockforge:latest
    command: ["mockforge", "ftp", "serve", "--host", "0.0.0.0"]
    ports:
      - "2121:2121"
    volumes:
      - ./ftp-config.yaml:/app/config/ftp-config.yaml
      - ./uploads:/tmp/uploads
    environment:
      - RUST_LOG=info

CI/CD Integration

GitHub Actions Example

# .github/workflows/ftp-test.yml
name: FTP Integration Tests

on: [push, pull_request]

jobs:
  ftp-test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Setup Rust
      uses: actions-rust-lang/setup-rust-toolchain@v1

    - name: Build MockForge
      run: cargo build --release

    - name: Start FTP Server
      run: |
        ./target/release/mockforge ftp serve --port 2121 &
        sleep 2

    - name: Run FTP Tests
      run: |
        # Test with lftp
        sudo apt-get update && sudo apt-get install -y lftp
        echo "Test file content" > test.txt
        lftp -c "open localhost:2121; put test.txt; ls; get test.txt -o downloaded.txt; quit"

        # Verify files
        test -f downloaded.txt
        grep -q "Test file content" downloaded.txt

Jenkins Pipeline

// Jenkinsfile
pipeline {
    agent any

    stages {
        stage('FTP Integration Test') {
            steps {
                sh 'cargo build --release'

                // Start FTP server in background
                sh './target/release/mockforge ftp serve --port 2121 &'
                sh 'sleep 3'

                // Run tests
                sh '''
                # Install FTP client
                apt-get update && apt-get install -y lftp

                # Create test file
                echo "Integration test content" > test.txt

                # Test FTP operations
                lftp -c "
                  open localhost:2121
                  put test.txt
                  ls
                  get test.txt -o downloaded.txt
                  quit
                "

                # Verify
                grep -q "Integration test content" downloaded.txt
                '''
            }
        }
    }
}

Troubleshooting

Common Issues

Connection Refused

# Check if server is running
netstat -tlnp | grep 2121

# Check server logs
mockforge ftp serve --port 2121 2>&1

Passive Mode Issues

# FTP clients may need passive mode
curl --ftp-pasv ftp://localhost:2121/

File Permission Issues

# Check file permissions in VFS
mockforge ftp vfs info /problematic-file.txt

# Check upload rules
mockforge ftp fixtures validate config.yaml

Memory Issues

# Monitor memory usage
ps aux | grep mockforge

# Use file storage for large files
# Configure storage type in upload rules

This completes the FTP implementation for MockForge. The server provides comprehensive FTP mocking capabilities with virtual file systems, template rendering, and configurable upload handling.

TCP Mocking

MockForge can mock arbitrary TCP services — anything from a custom binary protocol to a line-delimited text protocol — without you needing to write a parser. Configure a port, point it at a fixtures directory, and the server framing-decodes incoming data and replies based on matched fixtures.

This is the right tool when:

  • You’re testing a client that talks raw TCP (custom protocols, legacy systems, line-oriented protocols like Memcached or Redis-style RESP).
  • You need protocol-agnostic mocking — drop bytes in, get bytes out.
  • You want to validate your client’s framing/parsing logic against controlled error cases.

For HTTP / WebSocket / gRPC use the dedicated chapters; those have richer protocol-aware features (route matching, schema validation, streaming).

Quick Start

# Listen on the default port 9999, no fixtures
mockforge serve --tcp-port 9999

There is no standalone mockforge tcp command; the TCP server runs inside mockforge serve. Set the fixtures directory in the tcp config section.

Point a client at localhost:9999:

nc localhost 9999
> hello
< hello                # echo mode replies with the received bytes

Configuration

tcp:
  port: 9999                       # Listener port
  host: "0.0.0.0"                  # Bind address
  fixtures_dir: "./fixtures/tcp"   # Optional: fixture-driven responses
  timeout_secs: 300                # Per-connection idle timeout (5 min)
  max_connections: 100             # Concurrent connection cap
  read_buffer_size: 8192           # Per-read buffer (bytes)
  write_buffer_size: 8192          # Per-write buffer (bytes)
  enable_tls: false                # Wrap connections in TLS
  tls_cert_path: null              # Required when enable_tls: true
  tls_key_path: null               # Required when enable_tls: true
  echo_mode: false                 # Reply with received bytes when no fixture matches
  delimiter: null                  # Frame mode: e.g. [10] for newline-delimited

Echo mode

When echo_mode: true, any inbound bytes that don’t match a fixture are echoed back verbatim. Useful as a sanity check or for tests that just need a roundtrip without specific responses.

tcp:
  port: 9999
  echo_mode: true

Stream vs frame mode

delimiterBehavior
null (default)Stream mode — fixtures match on raw byte sequences arriving in any chunking
[10]Newline-delimited (LF) — each newline-terminated line is a discrete message
[13, 10]CRLF-delimited
[0]Null-byte-delimited
Any other byte sequenceCustom delimiter

Frame mode makes fixture authoring much easier for line-oriented protocols (Memcached, Redis-style RESP, custom telnet-style commands). Stream mode is the right choice when you control the framing yourself.

TLS

tcp:
  enable_tls: true
  tls_cert_path: "/etc/ssl/certs/mockforge.crt"
  tls_key_path: "/etc/ssl/private/mockforge.key"

Self-signed certs are fine for local dev; clients will need to skip verification (e.g. openssl s_client -connect host:port -CAfile mockforge.crt).

Fixtures

A TCP fixture is a request/response pair, optionally with a wait condition. Fixture files live in fixtures_dir and are picked up at startup.

# fixtures/tcp/echo-greeting.yaml
name: echo-greeting
match:
  bytes: "PING\n"          # exact byte match (LF in frame mode)
respond:
  bytes: "PONG\n"
  delay_ms: 5              # optional: simulate latency

For binary protocols, use base64:

name: handshake
match:
  base64: "SGVsbG8K"       # "Hello\n"
respond:
  base64: "V29ybGQK"       # "World\n"

For sequence-based scenarios (multi-step protocols), order matters; the server walks fixtures top-to-bottom for each connection.

CLI flags

# Embedded in `mockforge serve`
mockforge serve --spec api.yaml --tcp-port 9999

Host, fixtures directory, and connection limits are set in the tcp config section shown above.

Environment variables

MOCKFORGE_TCP_ENABLED=true
MOCKFORGE_TCP_PORT=9999
MOCKFORGE_TCP_HOST=0.0.0.0

Pairing with chaos

For latency, fault injection, or rate limiting on TCP traffic, use the chaos engine — it hooks every protocol on the same listener config surface. The connection_error_kind: tcp_reset knob is especially useful here for testing client reconnect behavior:

observability:
  chaos:
    enabled: true
    fault_injection:
      enabled: true
      connection_errors: true
      connection_error_probability: 0.05
      connection_error_kind: tcp_reset

5% of accepted TCP connections will get a kernel-level RST.

Where to go next

  • Chaos Engineering — fault injection on TCP connections
  • Load Testing — drive traffic at the TCP server with mockforge bench-chunked or a custom hyper client

Environment Variables

MockForge supports extensive configuration through environment variables. This page documents all available environment variables, their purposes, and usage examples.

Core Functionality

Server Control

  • MOCKFORGE_LATENCY_ENABLED=true|false (default: true)

    • Enable/disable response latency simulation
    • When disabled, responses are immediate
  • MOCKFORGE_FAILURES_ENABLED=true|false (default: false)

    • Enable/disable failure injection
    • When enabled, can simulate HTTP errors and timeouts
  • MOCKFORGE_OVERRIDES_ENABLED=true|false (default: true)

    • Sets the core.overrides_enabled config field (1/true enables; any other value disables)
    • Note: no code reads this field yet, so it does not currently turn the overrides: rules on or off; they apply whenever they are configured
  • MOCKFORGE_LOG_LEVEL=debug|info|warn|error (default: info)

    • Set the logging verbosity level
    • Available: debug, info, warn, error

Recording and Replay

Recording, replay, and proxy modes are configured via CLI flags (--record, --replay, --proxy-target) and YAML, not env vars. See the Recording & Capture chapter for the full surface.

HTTP Server Configuration

Server Settings

  • MOCKFORGE_HTTP_PORT=3000 (default: 3000)

    • Port for the HTTP server to listen on
  • MOCKFORGE_HTTP_HOST=127.0.0.1 (default: 0.0.0.0)

    • Host address for the HTTP server to bind to

The OpenAPI spec path is set via --spec, MOCKFORGE_OPENAPI_SPEC_URL, or the http.spec YAML field. CORS, request timeouts, and other middleware options are YAML-configured under the relevant section (see CLI --help).

Validation and Templating

  • MOCKFORGE_REQUEST_VALIDATION=enforce|warn|off (default: enforce)

    • Level of request validation
    • enforce: Reject invalid requests with error
    • warn: Log warnings but allow requests
    • off: Skip validation entirely
  • MOCKFORGE_RESPONSE_VALIDATION=true|false (default: false)

    • Enable validation of generated responses
    • Useful for ensuring response format compliance
  • MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true|false (default: false)

    • Enable template expansion in responses
    • Allows use of {{uuid}}, {{now}}, etc. in responses
  • MOCKFORGE_AGGREGATE_ERRORS=true|false (default: true)

    • Aggregate multiple validation errors into a single response
    • When enabled, returns all validation errors at once
  • MOCKFORGE_VALIDATION_STATUS=400|422 (default: 400)

    • HTTP status code for validation errors
    • 400: Bad Request (general)
    • 422: Unprocessable Entity (validation-specific)

WebSocket Server Configuration

Server Settings

  • MOCKFORGE_WS_PORT=3001 (default: 3001)

    • Port for the WebSocket server to listen on
  • MOCKFORGE_WS_HOST=127.0.0.1 (default: 0.0.0.0)

    • Host address for the WebSocket server to bind to

Connection timeouts are YAML-only (websocket.connection_timeout_secs).

Replay Configuration

  • MOCKFORGE_WS_REPLAY_FILE=path/to/replay.jsonl
    • Path to WebSocket replay file
    • Enables scripted WebSocket message sequences

gRPC Server Configuration

Server Settings

  • MOCKFORGE_GRPC_PORT=50051 (default: 50051)
    • Port for the gRPC server to listen on

Host binding for the gRPC server is YAML-only (grpc.host).

Admin UI Configuration

Server Settings

  • MOCKFORGE_ADMIN_ENABLED=true|false (default: false)

    • Enable/disable the Admin UI
    • When enabled, provides web interface for management
  • MOCKFORGE_ADMIN_PORT=9080 (default: 9080)

    • Port for the Admin UI server to listen on
  • MOCKFORGE_ADMIN_HOST=127.0.0.1 (default: 127.0.0.1)

    • Host address for the Admin UI server to bind to

UI Configuration

  • MOCKFORGE_ADMIN_MOUNT_PATH=/admin (default: none)

    • Mount path for embedded Admin UI
    • When set, Admin UI is available under HTTP server
  • MOCKFORGE_ADMIN_API_ENABLED=true|false (default: true)

    • Enable/disable Admin UI API endpoints
    • Controls whether /__mockforge/* endpoints are available

Data Generation Configuration

Faker Control

  • MOCKFORGE_RAG_ENABLED=true|false (default: false)

    • Enable Retrieval-Augmented Generation for data
    • Requires additional setup for LLM integration
  • MOCKFORGE_FAKE_TOKENS=true|false (default: true)

    • Enable/disable faker token expansion
    • Controls whether {{faker.email}} etc. work

RAG / LLM Provider

  • MOCKFORGE_RAG_PROVIDER=openai|anthropic|ollama (default: openai)
    • LLM provider for retrieval-augmented generation.
  • MOCKFORGE_RAG_API_KEY=<key> — provider API key (falls back to OPENAI_API_KEY when unset).
  • MOCKFORGE_RAG_API_ENDPOINT=<url> — custom endpoint, overrides the provider default.
  • MOCKFORGE_RAG_MODEL=<name> — e.g. gpt-4, claude-3-5-sonnet, llama3.
  • MOCKFORGE_RAG_TEMPERATURE=<float> (default: 0.7).
  • MOCKFORGE_RAG_MAX_TOKENS=<int> (default: 2048).
  • MOCKFORGE_RAG_CONTEXT_WINDOW=<int> (default: 4096).
  • MOCKFORGE_RAG_TIMEOUT_SECONDS=<int> (default: 30).
  • MOCKFORGE_RAG_MAX_RETRIES=<int> (default: 3).
  • OPENAI_API_KEY=<key> — fallback when MOCKFORGE_RAG_API_KEY is unset.
  • MOCKFORGE_EMBEDDING_PROVIDER=openai|local|ollama — provider for embeddings used by RAG.
  • MOCKFORGE_EMBEDDING_MODEL=<name> — e.g. text-embedding-3-small.
  • MOCKFORGE_EMBEDDING_ENDPOINT=<url> — custom endpoint.
  • MOCKFORGE_SIMILARITY_THRESHOLD=<float> (0.0–1.0) — minimum match score.

Registry / Marketplace

  • MOCKFORGE_REGISTRY_TOKEN=<token> — auth token for publishing scenarios or plugins to the registry. Required for mockforge scenario publish and similar commands.
  • MOCKFORGE_PLUGIN_REGISTRY_URL=<url> — registry endpoint used by mockforge plugin install / publish (default: the public mockforge.dev registry).

OpenAPI / Spec Loading

  • MOCKFORGE_OPENAPI_SPEC_URL=<url> — alternative to --spec; load the OpenAPI spec from a URL at startup. Useful in containerized deployments where the spec lives behind a static CDN.

Distributed Tracing (OpenTelemetry / OTLP)

  • MOCKFORGE_OTLP_ENDPOINT=<url> — OTLP collector endpoint (e.g. http://jaeger:4317 or http://otel-collector:4318).
  • MOCKFORGE_OTLP_SERVICE_NAME=<name> — service name attached to spans (default: mockforge).
  • MOCKFORGE_OTLP_SAMPLING_RATE=<float> — 0.0–1.0. 1.0 = trace every request.

Rate Limiting

  • MOCKFORGE_RATE_LIMIT_ENABLED=true|false — toggle the HTTP middleware rate limiter.
  • MOCKFORGE_RATE_LIMIT_DISABLED=true|false — explicit opt-out (overrides config-file enabled: true). Useful for --no-rate-limit parity in containers.
  • MOCKFORGE_RATE_LIMIT_RPM=<int> — global requests-per-minute cap.

Kafka Protocol

  • MOCKFORGE_KAFKA_ENABLED=true|false — start the Kafka mock listener.
  • MOCKFORGE_KAFKA_ADVERTISED_HOST=<host> — hostname advertised in metadata responses (defaults to the bind host).
  • MOCKFORGE_KAFKA_ADVERTISED_PORT=<int> — port advertised in metadata responses (defaults to the bind port).
  • MOCKFORGE_KAFKA_FIXTURES_DIR=path/to/kafka-fixtures — directory of pre-recorded Kafka topic fixtures.
  • MOCKFORGE_KAFKA_RECORDING_DB=path/to/recording.sqlite — SQLite file for recording produce/consume exchanges; when set, every Kafka exchange is persisted for replay.

AMQP / MQTT Protocol

  • MOCKFORGE_AMQP_RECORDING_DB=path/to/recording.sqlite — SQLite file for recording AMQP publish/deliver exchanges; when set, every exchange is persisted for replay. Unset or unusable path is a no-op.
  • MOCKFORGE_MQTT_RECORDING_DB=path/to/recording.sqlite — SQLite file for recording MQTT publish/deliver exchanges; when set, every exchange is persisted for replay. Unset or unusable path is a no-op.

Federation

  • MOCKFORGE_FEDERATION_POLL_URL=<url> — upstream MockForge instance to poll for shared workspaces.
  • MOCKFORGE_FEDERATION_POLL_TOKEN=<token> — auth token for the upstream poll.
  • MOCKFORGE_FEDERATION_POLL_INTERVAL_SECS=<int> — poll cadence (default: 60).
  • MOCKFORGE_FEDERATION_WORKSPACE_ID=<uuid> — workspace this instance federates into.

Encryption / Secret Storage

  • MOCKFORGE_ENCRYPTION_KEY=<base64-key> — base64-encoded AES-256 key used to encrypt config/data at rest.
  • MOCKFORGE_MASTER_KEY=<base64-key> — master KEK that wraps per-workspace data encryption keys.
  • MOCKFORGE_BYOK_ENCRYPTION_KEY=<base64-key> — bring-your-own-key override for workspace encryption.
  • MOCKFORGE_SECRET_PROVIDER=env|aws|vault|gcp|azure — backend used by the secret-resolution layer (default: env).
  • MOCKFORGE_SECRET_CACHE_TTL=<secs> — how long resolved secrets stay in the in-process cache.
  • MOCKFORGE_KMS_PROVIDER=aws|gcp|azure|vault — when set, MockForge fetches the master key from a managed KMS instead of using MOCKFORGE_MASTER_KEY.
  • MOCKFORGE_KMS_REGION=<region> — region for the KMS provider (e.g. us-east-1).
  • MOCKFORGE_VAULT_ADDR=<url> — Vault server address when using MOCKFORGE_KMS_PROVIDER=vault.
  • MOCKFORGE_VAULT_TOKEN=<token> — Vault auth token.

Database (registry server / collab)

These apply to the multi-tenant registry server and the collab workspace backend; the OSS local mock server doesn’t need them.

  • MOCKFORGE_DB_TYPE=sqlite|postgres — backing store for the registry / collab.
  • MOCKFORGE_DB_CONNECTION=<url> — connection string (e.g. postgres://user:pass@host/db or sqlite:./mockforge.db).

Fixtures and Testing

Fixtures Configuration

  • MOCKFORGE_FIXTURES_DIR=path/to/fixtures (default: ./fixtures)
    • Directory where fixtures are stored
    • Used for recording and replaying HTTP requests

Authentication (OIDC)

  • MOCKFORGE_OIDC_ENABLED=true|false — enable OpenID Connect for the admin API and proxied routes.
  • MOCKFORGE_OIDC_ISSUER=<url> — issuer URL whose /.well-known/openid-configuration MockForge will fetch.
  • MOCKFORGE_OIDC_CONFIG=<path> — path to a YAML/JSON file overriding individual OIDC discovery fields.
  • MOCKFORGE_OIDC_SECRET=<client-secret> — confidential-client secret for the configured client_id.

Registry session cookies (registry server)

  • MOCKFORGE_SESSION_COOKIE_SECURE=true|false — set Secure; SameSite=None on the mockforge_session / mockforge_refresh auth cookies. Required for hosted HTTPS deployments where the admin UI is served from a different origin than the API; self-hosted plain-HTTP setups keep SameSite=Lax without Secure.

Hot Reload

Watch the spec / config / fixtures dirs and rebuild routes on change without restarting.

  • MOCKFORGE_HOT_RELOAD_ENABLED=true|false — master switch.
  • MOCKFORGE_HOT_RELOAD_SPEC=true|false — watch the OpenAPI spec file.
  • MOCKFORGE_HOT_RELOAD_FIXTURES=true|false — watch the fixtures directory.
  • MOCKFORGE_HOT_RELOAD_DEBOUNCE=<ms> — coalesce rapid filesystem events into a single reload.
  • MOCKFORGE_HOT_RELOAD_INTERVAL=<ms> — polling fallback when filesystem events aren’t available.
  • MOCKFORGE_HOT_RELOAD_TIMEOUT=<ms> — upper bound on a single reload before it’s aborted.
  • MOCKFORGE_HOT_RELOAD_GRACEFUL=true|false — drain in-flight requests before swapping routes.
  • MOCKFORGE_HOT_RELOAD_VALIDATE=true|false — re-run validation on every reload (safer; slower).

Plugins

  • MOCKFORGE_PLUGINS_ENABLED=true|false — load .so/.dylib/.wasm plugins on startup.
  • MOCKFORGE_PLUGIN_CACHE_DIR=<path> — where downloaded plugins are cached.
  • MOCKFORGE_PLUGIN_TIMEOUT_MS=<ms> — per-invocation timeout for plugin calls.
  • MOCKFORGE_PLUGIN_MAX_CONCURRENT=<int> — max concurrent plugin invocations across the process.
  • MOCKFORGE_PLUGIN_MAX_CPU=<percent> — CPU budget per plugin (0–100).
  • MOCKFORGE_PLUGIN_MAX_MEMORY=<bytes> — memory cap per plugin.
  • MOCKFORGE_PLUGIN_MAX_MODULE_SIZE=<bytes> — max accepted plugin binary size.
  • MOCKFORGE_PLUGIN_NETWORK_ACCESS=true|false — allow plugins to make outbound network calls.

Compression

  • MOCKFORGE_COMPRESSION_ENABLED=true|false — gzip/deflate/zstd response bodies above the threshold.
  • MOCKFORGE_COMPRESSION_ALGORITHM=gzip|deflate|zstd|br — preferred compression codec when the client accepts multiple.
  • MOCKFORGE_COMPRESSION_LEVEL=<int> — codec-specific level (e.g. 1–9 for gzip).

Resilience

  • MOCKFORGE_CIRCUIT_BREAKER_ENABLED=true|false — wrap upstream calls (proxy / record-replay) in a circuit breaker.
  • MOCKFORGE_CIRCUIT_BREAKER_THRESHOLD=<int> — consecutive failures before the breaker opens.
  • MOCKFORGE_POOL_MAX_CONNECTIONS=<int> — outbound HTTP connection pool size.
  • MOCKFORGE_POOL_IDLE_TIMEOUT=<secs> — close idle connections after this duration.

Performance Tuning

  • MOCKFORGE_WORKER_THREADS=<int> — Tokio worker-thread count (default: number of CPU cores).
  • MOCKFORGE_MAX_BODY_SIZE=<bytes> — reject inbound HTTP bodies larger than this.

Proxy / Record-Replay

  • MOCKFORGE_PROXY_UPSTREAM=<url> — when set, requests with no matching mock are proxied here. Pair with mockforge serve --recorder (or the recorder admin API) to capture upstream traffic for replay.
  • MOCKFORGE_PROXY_SPEC=<path> — OpenAPI/Swagger spec (JSON or YAML) backing the proxy’s passive conformance tap (#864).
  • MOCKFORGE_PROXY_VALIDATE_CONFORMANCE=true|false — validate proxied requests against the spec and report violations; requires MOCKFORGE_PROXY_SPEC.
  • MOCKFORGE_PROXY_VALIDATE_CONFORMANCE_STRICT=true|false — additionally reject non-conforming requests with a diagnostic response instead of forwarding.

Tunneling

  • MOCKFORGE_TUNNEL_SERVER_URL=<url> — control-plane URL for the MockForge tunnel server (used when mockforge tunnel start).
  • MOCKFORGE_TUNNEL_AUTH_TOKEN=<token> — auth token for the tunnel control plane.

Observability

Metrics CSV Log

  • MOCKFORGE_METRICS_LOG_FILE=path/to/metrics.csv
    • When set, the admin server’s system-monitoring task appends one CSV row every 10 s with timestamp,cpu_pct,mem_mb,total_reqs,err_rate.
    • Survives restarts; chartable in any spreadsheet, Grafana, or dashboarding tool.
    • Example: MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge-metrics.csv
    • The TUI dashboard also tracks lifetime peak CPU%, memory MB, and error rate in-memory and renders them as current (peak X) next to the live values.

Configuration Files

The config file path is set via --config <path>, not env var. MockForge also auto-discovers mockforge.yaml / mockforge.yml / mockforge.json in the working directory.

Usage Examples

Basic HTTP Server with OpenAPI

export MOCKFORGE_OPENAPI_SPEC_URL=file://./examples/openapi-demo.json
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true
export MOCKFORGE_ADMIN_ENABLED=true
cargo run -p mockforge-cli -- serve --http-port 3000 --admin-port 9080

Full WebSocket Support

export MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl
export MOCKFORGE_WS_PORT=3001
export MOCKFORGE_OPENAPI_SPEC_URL=file://./examples/openapi-demo.json
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true
cargo run -p mockforge-cli -- serve --admin

Development Setup

export MOCKFORGE_LOG_LEVEL=debug
export MOCKFORGE_LATENCY_ENABLED=false
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true
export MOCKFORGE_ADMIN_ENABLED=true
export MOCKFORGE_OPENAPI_SPEC_URL=file://./examples/openapi-demo.json
cargo run -p mockforge-cli -- serve

Production Setup

export MOCKFORGE_LOG_LEVEL=warn
export MOCKFORGE_LATENCY_ENABLED=true
export MOCKFORGE_FAILURES_ENABLED=false
export MOCKFORGE_REQUEST_VALIDATION=enforce
export MOCKFORGE_ADMIN_ENABLED=false
export MOCKFORGE_OPENAPI_SPEC_URL=file://./path/to/production-spec.json
cargo run -p mockforge-cli -- serve --http-port 80

Environment Variable Priority

Environment variables override configuration file settings. CLI flags take precedence over both. The priority order is:

  1. CLI flags (highest priority)
  2. Environment variables
  3. Configuration file settings
  4. Default values (lowest priority)

Security Considerations

  • Be careful with MOCKFORGE_ADMIN_ENABLED=true in production
  • Consider setting restrictive host bindings (127.0.0.1) for internal use
  • Use MOCKFORGE_FAKE_TOKENS=false for deterministic testing
  • Review CORS settings for cross-origin requests

Troubleshooting

Common Issues

  1. Environment variables not taking effect

    • Check variable names for typos
    • Ensure variables are exported before running the command
    • Use env | grep MOCKFORGE to verify variables are set
  2. Port conflicts

    • Use different ports via MOCKFORGE_HTTP_PORT, MOCKFORGE_WS_PORT, etc.
    • Check what processes are using ports with netstat -tlnp
  3. OpenAPI spec not loading

    • Verify file path in MOCKFORGE_OPENAPI_SPEC_URL
    • Ensure JSON/YAML syntax is valid
    • Check file permissions
  4. Template expansion not working

    • Set MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true
    • Verify token syntax (e.g., {{uuid}} not {uuid})

Operator and Deployment Variables

These are read by the hosted/cloud components (registry server, plugin host, plugin egress proxy, test runner) rather than by mockforge serve. Most are unset in a normal self-hosted deployment and only matter when running the managed stack. Defaults below are the values the code falls back to.

HTTP keep-alive hints

  • MOCKFORGE_HTTP_KEEPALIVE_TIMEOUT_SECS (default: 120)
    • Idle timeout advertised in the Keep-Alive response header
  • MOCKFORGE_HTTP_KEEPALIVE_MAX_REQUESTS (default: 1000)
    • Max requests per connection advertised in the Keep-Alive response header

Contract diff and drift capture

  • MOCKFORGE_CONTRACT_DIFF_MAX_BODY_MB (default: 10)
    • Largest response body, in MB, the contract-diff middleware will buffer
  • MOCKFORGE_DRIFT_MAX_BODY_MB (default: 10)
    • Same cap for the drift-tracking middleware
  • MOCKFORGE_CONTRACT_PROBE_INTERVAL_SECS (default: 1800)
    • Interval for the background contract probe. Values below 60 are ignored

Capture forwarding (cloud sync)

  • MOCKFORGE_CLOUD_CAPTURES_FORWARDER_URL (default: unset)
    • Endpoint captures are forwarded to. Falls back to MOCKFORGE_CAPTURE_INGEST_URL. Forwarding is off when neither is set
  • MOCKFORGE_CAPTURE_FORWARDER_BUFFER (default: 1024)
    • In-memory queue depth for pending captures
  • MOCKFORGE_CAPTURE_FORWARDER_TIMEOUT_MS (default: 5000)
    • HTTP timeout for each forward attempt

Kafka

  • MOCKFORGE_KAFKA_OFFSETS_DB (default: unset)
    • Path to persist consumer-group offsets. Unset or empty keeps offsets in memory only, so they are lost on restart

Observability

  • MOCKFORGE_OTLP_GRPC_PORT (default: 4317)
    • Port the registry server listens on for OTLP/gRPC telemetry

Hosted deployments

  • MOCKFORGE_CLOUD_PLUGINS_IMAGE (default: ghcr.io/saasy-solutions/mockforge-cloud-plugins:latest)
    • Container image for plugin-enabled hosted mocks. Non-plugin deployments use MOCKFORGE_DOCKER_IMAGE
  • MOCKFORGE_HOSTED_OVERAGE_CEILING_MULT (default: 0)
    • Multiple of the plan limit at which hosted traffic is cut off. 0 disables the ceiling. Values must be positive to take effect
  • MOCKFORGE_MANAGEMENT_TOKEN (default: unset)
    • Set by the registry on every hosted mock. When set, mockforge serve rejects writes (anything but GET, HEAD, OPTIONS) to MockForge’s own control routes (/__mockforge/*, /api/chaos, /api/recorder, /api/world-state, and the other management APIs) with 401 unless the request carries the token in X-MockForge-Management-Token or Authorization: Bearer. Reads and your mocked API are unaffected. Leave it unset for self-hosted servers

Incident dispatch

  • MOCKFORGE_PAGERDUTY_ENQUEUE_URL (default: https://events.pagerduty.com/v2/enqueue)
    • Override for the PagerDuty Events API endpoint, for testing or a proxy

Platform LLM (managed test generation)

  • MOCKFORGE_PLATFORM_LLM_PROVIDER (default: openai)
  • MOCKFORGE_PLATFORM_LLM_MODEL (default: gpt-4o-mini)
  • MOCKFORGE_PLATFORM_LLM_ENDPOINT (default: unset)
    • Base URL override, for a self-hosted or proxied provider

Test runner

  • MOCKFORGE_RUNNER_QUEUE_KEY (default: test_runs:queued)
    • Redis key the runner pops queued test runs from
  • MOCKFORGE_RUNNER_MAX_CONCURRENT_JOBS (default: 4)
  • MOCKFORGE_RUNNER_POLL_TIMEOUT_SECS (default: 5)

Plugin egress proxy

  • MOCKFORGE_PLUGIN_EGRESS_LISTEN (default: 127.0.0.1:8125)
    • Listen address for the egress proxy
  • MOCKFORGE_PLUGIN_EGRESS_ALLOWLIST (default: unset)
    • Comma-separated hosts plugins may reach. Takes precedence over the file form
  • MOCKFORGE_PLUGIN_EGRESS_ALLOWLIST_FILE (default: unset)
    • Path to an allowlist file, one host per line

Plugin host

  • MOCKFORGE_PLUGIN_HOST_SOCKET (default: /tmp/plugin-host.sock)
    • Unix socket the plugin host listens on
  • MOCKFORGE_PLUGIN_HOST_SOCKET_MODE (default: platform default)
    • Permission bits for that socket. Accepts 0o660, 660, 0660 or 0x1B0
  • MOCKFORGE_PLUGIN_HOST_SIGNATURE_MODE=required|optional (default: optional)
    • Whether plugin signatures are enforced. An unrecognised value falls back to optional with a warning, so set this explicitly in production

Trusted signing keys, one of:

  • MOCKFORGE_PLUGIN_HOST_TRUSTED_KEYS (default: unset)
    • Inline comma-separated public keys
  • MOCKFORGE_PLUGIN_HOST_TRUSTED_KEYS_FILE (default: unset)
    • Path to a file of public keys

Remote trust root, blocklist, rotation and metrics are each off unless their URL is set. The bearer and interval variables only apply once the matching URL is present:

Trust root:

  • MOCKFORGE_PLUGIN_HOST_TRUST_ROOT_URL (default: unset, feature off)
  • MOCKFORGE_PLUGIN_HOST_TRUST_ROOT_BEARER (default: unset)
  • MOCKFORGE_PLUGIN_HOST_TRUST_ROOT_INTERVAL_SECS (default: built-in interval)

Blocklist:

  • MOCKFORGE_PLUGIN_HOST_BLOCKLIST_URL (default: unset, feature off)
  • MOCKFORGE_PLUGIN_HOST_BLOCKLIST_BEARER (default: unset)
  • MOCKFORGE_PLUGIN_HOST_BLOCKLIST_INTERVAL_SECS (default: built-in interval)

Key rotation:

  • MOCKFORGE_PLUGIN_HOST_ROTATION_INTERVAL_SECS (default: built-in interval)
  • MOCKFORGE_PLUGIN_HOST_ROTATION_BEARER (default: unset)

Metrics export:

  • MOCKFORGE_PLUGIN_HOST_METRICS_URL (default: unset, export off)
  • MOCKFORGE_PLUGIN_HOST_METRICS_BEARER (default: unset)
  • MOCKFORGE_PLUGIN_HOST_METRICS_FLUSH_INTERVAL_SECS (default: built-in interval)
  • MOCKFORGE_PLUGIN_HOST_METRICS_QUEUE_SIZE (default: built-in queue depth)

Test-only escape hatches

Both relax SSRF protection and must never be set in production. Each accepts 1 or true; anything else leaves the guard strict.

  • MOCKFORGE_SSRF_ALLOW_LOOPBACK (default: unset, guard strict)
    • Allows conformance/test-run targets to point at loopback addresses
  • MOCKFORGE_SSO_ALLOW_INSECURE_ISSUERS (default: unset, guard strict)
    • Allows http:// and localhost OIDC issuers. Logs a warning when set, because it disables the issuer SSRF guard that protects the verified-domain trust model

For more detailed configuration options, see the Configuration Files documentation.

Configuration Files

MockForge supports comprehensive configuration through YAML files as an alternative to environment variables. This page documents the configuration file format, options, and usage.

Quick Start

Initialize a New Configuration

# Create a new project with template configuration
mockforge init my-project

# Or initialize in current directory
mockforge init .

This creates a mockforge.yaml file with sensible defaults and example configurations.

Validate Your Configuration

# Validate configuration file
mockforge config validate

# Validate specific file
mockforge config validate --config my-config.yaml

See the Configuration Validation Guide for detailed validation instructions.

Complete Configuration Template

For a fully documented configuration template with all available options, see: config.template.yaml

This template includes:

  • Every configuration option with inline comments
  • Default values and valid ranges
  • Example configurations for common scenarios
  • Links to detailed documentation

Configuration File Location

MockForge looks for configuration files in the following order:

  1. Path specified by --config CLI flag
  2. Path specified by MOCKFORGE_CONFIG_FILE environment variable
  3. Default location: ./mockforge.yaml or ./mockforge.yml
  4. No configuration file (uses defaults)

Basic Configuration Structure

# MockForge Configuration Example
# This file demonstrates all available configuration options

# HTTP server configuration
http:
  port: 3000
  host: "0.0.0.0"
  openapi_spec: "examples/openapi-demo.json"
  cors_enabled: true
  request_timeout_secs: 30
  request_validation: "enforce"
  aggregate_validation_errors: true
  validate_responses: false
  response_template_expand: true
  skip_admin_validation: true

# WebSocket server configuration
websocket:
  port: 3001
  host: "0.0.0.0"
  replay_file: "examples/ws-demo.jsonl"
  connection_timeout_secs: 300

# gRPC server configuration
grpc:
  port: 50051
  host: "0.0.0.0"

# Admin UI configuration
admin:
  enabled: true
  port: 9080
  host: "127.0.0.1"
  mount_path: null
  api_enabled: true

# Core MockForge configuration
core:
  latency_enabled: true
  failures_enabled: false

# Logging configuration
logging:
  level: "info"
  json_format: false
  file_path: null
  max_file_size_mb: 10
  max_files: 5

# Data generation configuration
data:
  default_rows: 100
  default_format: "json"
  locale: "en"

HTTP Server Configuration

Basic Settings

http:
  port: 3000                    # Server port
  host: "0.0.0.0"              # Bind address (0.0.0.0 for all interfaces)
  cors_enabled: true           # Enable CORS headers
  request_timeout_secs: 30     # Request timeout in seconds

OpenAPI Integration

http:
  openapi_spec: "path/to/spec.json"  # OpenAPI spec file for HTTP server
  # Alternative: use URL
  openapi_spec: "https://example.com/api-spec.yaml"

Validation and Response Handling

http:
  request_validation: "enforce"      # off|warn|enforce
  aggregate_validation_errors: true  # Combine multiple errors
  validate_responses: false          # Validate generated responses
  response_template_expand: true     # Enable {{uuid}}, {{now}} etc.
  skip_admin_validation: true        # Skip validation for admin endpoints

Validation Overrides

http:
  validation_overrides:
    "POST /users/{id}": "warn"      # Override validation level per endpoint
    "GET /internal/health": "off"  # Skip validation for specific endpoints

WebSocket Server Configuration

websocket:
  port: 3001                          # Server port
  host: "0.0.0.0"                    # Bind address
  replay_file: "path/to/replay.jsonl" # WebSocket replay file
  connection_timeout_secs: 300       # Connection timeout in seconds

gRPC Server Configuration

grpc:
  port: 50051       # Server port
  host: "0.0.0.0"  # Bind address
  proto_dir: null  # Directory containing .proto files
  tls: null        # TLS configuration (optional)

Admin UI Configuration

Standalone Mode (Default)

admin:
  enabled: true
  port: 9080
  host: "127.0.0.1"
  api_enabled: true

Embedded Mode

admin:
  enabled: true
  mount_path: "/admin"  # Mount under HTTP server
  api_enabled: true     # Enable API endpoints
  # Note: port/host ignored when mount_path is set

Core Configuration

Latency Simulation

core:
  latency_enabled: true
  default_latency:
    base_ms: 50
    jitter_ms: 20
    distribution: "fixed"  # fixed, normal, or pareto

  # For normal distribution
  # std_dev_ms: 10.0

  # For pareto distribution
  # pareto_shape: 2.0

  min_ms: 10      # Minimum latency
  max_ms: 5000    # Maximum latency (optional)

  # Per-operation overrides
  tag_overrides:
    auth: 100
    payments: 200

Failure Injection

core:
  failures_enabled: true
  failure_config:
    global_error_rate: 0.05  # 5% global error rate

    # Default status codes for failures
    default_status_codes: [500, 502, 503, 504]

    # Per-tag error rates and status codes
    tag_configs:
      auth:
        error_rate: 0.1      # 10% error rate for auth operations
        status_codes: [401, 403]
        error_message: "Authentication failed"
      payments:
        error_rate: 0.02     # 2% error rate for payments
        status_codes: [402, 503]
        error_message: "Payment processing failed"

    # Tag filtering
    include_tags: []         # Empty means all tags included
    exclude_tags: ["health", "metrics"]  # Exclude these tags

Proxy Configuration

core:
  proxy:
    upstream_url: "http://api.example.com"
    timeout_seconds: 30

Logging Configuration

logging:
  level: "info"           # debug|info|warn|error
  json_format: false      # Use JSON format for logs
  file_path: "logs/mockforge.log"  # Optional log file
  max_file_size_mb: 10    # Rotate when file reaches this size
  max_files: 5           # Keep this many rotated log files

Data Generation Configuration

data:
  default_rows: 100       # Default number of rows to generate
  default_format: "json"  # Default output format
  locale: "en"           # Locale for generated data

  # Custom faker templates
  templates:
    custom_user:
      name: "{{faker.name}}"
      email: "{{faker.email}}"
      department: "{{faker.word}}"

  # RAG (Retrieval-Augmented Generation) configuration
  rag:
    enabled: false
    api_endpoint: null
    api_key: null
    model: null
    context_window: 4000

Advanced Configuration

Response Overrides

Patch generated responses without editing the spec. See Response Override Rules for targets, conditions, and the runtime API.

overrides:
  - targets: ["operation:getUser"]     # Target specific operations
    patch:
      - op: add
        path: /metadata/requestId
        value: "{{uuid}}"
      - op: replace
        path: /user/createdAt
        value: "{{now}}"
      - op: add
        path: /user/score
        value: "{{rand.float}}"

  - targets: ["tag:Payments"]          # Target by tags
    patch:
      - op: replace
        path: /payment/status
        value: "FAILED"

Latency Profiles

# External latency profiles file
latency_profiles: "config/latency.yaml"

# Example latency configuration:
# operation:getUser:
#   fixed_ms: 120
#   jitter_ms: 80
#   fail_p: 0.0
#
# tag:Payments:
#   fixed_ms: 200
#   jitter_ms: 300
#   fail_p: 0.05
#   fail_status: 503

Configuration Examples

Development Configuration

# Development setup with debugging and fast responses
http:
  port: 3000
  response_template_expand: true
  request_validation: "warn"

admin:
  enabled: true
  port: 9080

core:
  latency_enabled: false  # Disable latency for faster development

logging:
  level: "debug"
  json_format: false

Testing Configuration

# Testing setup with deterministic responses
http:
  port: 3000
  response_template_expand: false  # Disable random tokens for determinism

core:
  latency_enabled: false

data:
  rag:
    enabled: false  # Disable RAG for consistent test data

Production Configuration

# Production setup with monitoring and reliability
http:
  port: 80
  host: "0.0.0.0"
  request_validation: "enforce"
  cors_enabled: false

admin:
  enabled: false  # Disable admin UI in production

core:
  latency_enabled: true
  failures_enabled: false

logging:
  level: "warn"
  json_format: true
  file_path: "/var/log/mockforge.log"

Configuration File Validation

MockForge validates configuration files at startup. Common issues:

  1. Invalid YAML syntax - Check indentation and quotes
  2. Missing required fields - Some fields like request_timeout_secs are required
  3. Invalid file paths - Ensure OpenAPI spec and replay files exist
  4. Port conflicts - Choose unique ports for each service

Configuration Precedence

Configuration values are resolved in this priority order:

  1. CLI flags (highest priority)
  2. Environment variables
  3. Configuration file
  4. Default values (lowest priority)

This allows you to override specific values without changing your configuration file.

Hot Reloading

Configuration changes require a server restart to take effect. For development, you can use:

# Watch for changes and auto-restart
cargo watch -x "run -p mockforge-cli -- serve --config config.yaml"

For more information on environment variables, see the Environment Variables documentation.

Advanced Options

MockForge provides extensive advanced configuration options for enterprise-grade API mocking, testing, and chaos engineering scenarios. This guide covers sophisticated features like traffic shaping, time travel, ML-based anomaly detection, multi-tenancy, and advanced orchestration.

Traffic Shaping and Bandwidth Control

MockForge supports advanced traffic shaping beyond simple latency simulation, including bandwidth throttling and burst control.

Bandwidth Throttling

Configure bandwidth limits to simulate network constraints:

# mockforge.yaml
traffic_shaping:
  bandwidth:
    enabled: true
    max_bytes_per_sec: 1024000  # 1MB/s
    burst_capacity_bytes: 1048576  # 1MB burst allowance

    # Tag-based overrides for specific routes
    tag_overrides:
      premium: 5242880  # 5MB/s for premium routes
      admin: 0  # Unlimited for admin routes

Packet Loss Simulation

Simulate network unreliability with configurable packet loss:

traffic_shaping:
  packet_loss:
    enabled: true
    loss_rate: 0.05  # 5% packet loss
    burst_loss_probability: 0.1  # 10% chance of burst loss
    burst_length: 5  # 5 consecutive packets lost in burst

    # Route-specific overrides
    route_overrides:
      "/api/health": 0.0  # No loss for health checks
      "/api/slow/*": 0.2  # 20% loss for slow endpoints

Traffic shaping is configured via the chaos engine’s observability.chaos.traffic_shaping block (YAML only — no dedicated env vars). See Chaos Engineering and Rate Limiting for the full surface.

Time Travel and Temporal Testing

MockForge’s time travel capabilities allow testing time-dependent behavior without waiting for real time to pass.

Virtual Clock Configuration

# mockforge.yaml
time_travel:
  enabled: true
  initial_time: "2024-01-01T00:00:00Z"
  scale_factor: 1.0  # 1.0 = real time, 2.0 = 2x speed

  # Scheduled time jumps
  schedule:
    - at: "2024-01-01T01:00:00Z"
      jump_to: "2024-01-01T06:00:00Z"
    - at: "2024-01-01T12:00:00Z"
      advance_by: "1d"

Time Travel API

Control time programmatically through the Admin UI or REST API:

# Set virtual time
curl -X POST http://localhost:9080/api/v2/time/set \
  -H "Content-Type: application/json" \
  -d '{"time": "2024-01-01T12:00:00Z"}'

# Advance time
curl -X POST http://localhost:9080/api/v2/time/advance \
  -H "Content-Type: application/json" \
  -d '{"duration": "1h"}'

# Enable/disable time travel
curl -X POST http://localhost:9080/api/v2/time/enable \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

Testing Time-Dependent Logic

# Example: Testing token expiry
routes:
  - path: /api/auth/validate
    method: GET
    response:
      status: 200
      condition: "time_travel.now < time_travel.parse('2024-01-01T02:00:00Z')"
      body: |
        {
          "valid": true,
          "expires_at": "2024-01-01T02:00:00Z"
        }

  - path: /api/auth/validate
    method: GET
    response:
      status: 401
      condition: "time_travel.now >= time_travel.parse('2024-01-01T02:00:00Z')"
      body: |
        {
          "error": "Token expired",
          "expired_at": "2024-01-01T02:00:00Z"
        }

ML-Based Anomaly Detection

MockForge integrates machine learning for intelligent anomaly detection in system behavior.

Anomaly Detection Configuration

# mockforge.yaml
anomaly_detection:
  enabled: true

  # Detection parameters
  config:
    std_dev_threshold: 3.0  # Standard deviations for anomaly
    min_baseline_samples: 30  # Minimum samples for baseline
    moving_average_window: 10  # Smoothing window
    enable_seasonal: true  # Account for seasonal patterns
    seasonal_period: 24  # Hours in daily cycle
    sensitivity: 0.7  # Detection sensitivity (0.0-1.0)

  # Metrics to monitor
  monitored_metrics:
    - name: response_time_ms
      baseline_samples: 100
      alert_on_anomaly: true
      severity_threshold: high

    - name: error_rate
      baseline_samples: 50
      alert_on_anomaly: true
      severity_threshold: medium

    - name: request_throughput
      baseline_samples: 100
      alert_on_anomaly: false
      severity_threshold: high

  # Collective anomaly detection
  collective_detection:
    enabled: true
    metric_groups:
      - name: api_health
        metrics:
          - response_time_ms
          - error_rate
          - request_throughput
        min_affected_metrics: 2

Anomaly Response Actions

Configure automatic responses to detected anomalies:

anomaly_detection:
  response_actions:
    - trigger: high_severity_anomaly
      action: circuit_breaker
      duration: 5m
      routes: ["/api/*"]

    - trigger: collective_anomaly
      action: failover
      target: backup_service
      routes: ["/api/critical/*"]

    - trigger: performance_degradation
      action: scale_up
      threshold: 2.0  # 2x normal response time

Chaos Mesh Integration

Integrate with Chaos Mesh for Kubernetes-native chaos engineering.

Chaos Mesh Configuration

# mockforge.yaml
chaos_mesh:
  enabled: true
  api_url: https://kubernetes.default.svc
  namespace: chaos-testing

  # Default experiment settings
  defaults:
    mode: one  # one, all, fixed, fixed-percent, random-max-percent
    duration: 5m

  # Pre-configured experiments
  experiments:
    - name: pod-kill-test
      type: PodChaos
      action: pod-kill
      selector:
        namespaces:
          - production
        label_selectors:
          app: api-gateway
          tier: backend
      mode: one
      duration: 30s
      schedule: "*/5 * * * *"  # Every 5 minutes

    - name: network-latency-test
      type: NetworkChaos
      action: delay
      selector:
        namespaces:
          - production
        label_selectors:
          app: database
      delay:
        latency: 100ms
        jitter: 10ms
        correlation: "50"
      duration: 3m

    - name: cpu-stress-test
      type: StressChaos
      selector:
        namespaces:
          - staging
        label_selectors:
          app: worker-service
      stressors:
        cpu_workers: 4
        cpu_load: 80
      duration: 10m

Chaos Experiment Orchestration

# Orchestrate chaos experiments with MockForge scenarios
orchestration:
  name: chaos-testing-workflow
  description: Comprehensive chaos testing with monitoring

  steps:
    - name: baseline_measurement
      type: metrics_collection
      duration: 5m

    - name: pod_failure_injection
      type: chaos_mesh
      experiment: pod-kill-test
      wait_for_completion: true

    - name: anomaly_detection
      type: ml_detection
      metrics: [response_time_ms, error_rate]
      alert_threshold: high

    - name: network_chaos
      type: chaos_mesh
      experiment: network-latency-test

    - name: recovery_verification
      type: health_check
      endpoints: ["/api/health", "/api/status"]
      timeout: 30s

Multi-Tenancy Configuration

MockForge supports multi-tenant deployments with configurable plans and quotas.

Tenant Plans Configuration

# mockforge.yaml
multi_tenancy:
  enabled: true

  # Define tenant plans
  plans:
    free:
      quotas:
        max_scenarios: 5
        max_concurrent_executions: 1
        max_orchestrations: 3
        max_templates: 5
        max_requests_per_minute: 50
        max_storage_mb: 50
        max_users: 1
        max_experiment_duration_secs: 600

      permissions:
        can_create_scenarios: true
        can_execute_scenarios: true
        can_view_observability: false
        can_manage_resilience: false
        can_use_advanced_features: false
        can_integrate_external: false
        can_use_ml_features: false
        can_manage_users: false

    professional:
      quotas:
        max_scenarios: 100
        max_concurrent_executions: 20
        max_orchestrations: 50
        max_templates: 100
        max_requests_per_minute: 1000
        max_storage_mb: 5000
        max_users: 25
        max_experiment_duration_secs: 14400

      permissions:
        can_create_scenarios: true
        can_execute_scenarios: true
        can_view_observability: true
        can_manage_resilience: true
        can_use_advanced_features: true
        can_integrate_external: true
        can_use_ml_features: true
        can_manage_users: true

  # Default tenants
  tenants:
    - name: acme-corp
      plan: professional
      enabled: true
      metadata:
        organization: Acme Corporation
        contact: [email protected]
        environment: production

Tenant Isolation

Configure tenant-specific resources and isolation:

multi_tenancy:
  isolation:
    # Database isolation
    database:
      separate_schemas: true
      schema_prefix: "tenant_"

    # File system isolation
    filesystem:
      tenant_directories: true
      shared_resources: ["global-templates"]

    # Network isolation
    network:
      tenant_subdomains: true
      shared_ports: [80, 443]

Plugin System Configuration

Advanced plugin configuration for extending MockForge functionality.

Plugin Registry Configuration

# mockforge.yaml
plugins:
  enabled: true

  # Plugin registry settings
  registry:
    auto_discover: true
    plugin_dirs:
      - /etc/mockforge/plugins
      - ~/.mockforge/plugins
      - ./custom-plugins

  # Built-in plugins
  builtin:
    - id: custom-fault-injector
      enabled: true
      config:
        fault_probability: 0.1
        default_timeout_ms: 5000

    - id: metrics-collector
      enabled: true
      config:
        export_interval_secs: 60
        buffer_size: 1000

  # Custom plugins
  custom:
    - id: database-fault-injector
      enabled: true
      path: /etc/mockforge/plugins/database_fault.so
      config:
        connection_timeout_ms: 5000
        query_timeout_ms: 30000
        fault_types:
          - connection_timeout
          - query_error
          - slow_query
          - deadlock

    - id: prometheus-exporter
      enabled: true
      path: /etc/mockforge/plugins/prometheus.so
      config:
        export_port: 9090
        metrics_path: /metrics
        include_labels:
          - tenant_id
          - scenario_id
          - experiment_type

  # Plugin hooks
  hooks:
    - type: logging
      enabled: true
      config:
        log_level: info
        include_context: true

    - type: metrics
      enabled: true
      config:
        track_execution_time: true
        track_success_rate: true

    - type: rate_limiting
      enabled: true
      config:
        max_executions_per_minute: 100
        burst_size: 20

Plugin Security

Configure plugin execution security:

plugins:
  security:
    # Sandbox configuration
    sandbox:
      enabled: true
      memory_limit_mb: 100
      cpu_limit_percent: 50
      network_access: deny
      filesystem_access: restricted

    # Plugin signing
    signing:
      enabled: true
      trusted_keys:
        - "mockforge-official"
        - "enterprise-customer-key"

    # Resource limits
    limits:
      max_plugins_per_tenant: 10
      max_plugin_memory_mb: 50
      max_plugin_timeout_secs: 30

Advanced Orchestration

Complex scenario orchestration with conditional logic and dependencies.

Orchestration Configuration

# mockforge.yaml
orchestration:
  name: advanced-chaos-scenario
  description: Comprehensive chaos test with ML detection and multi-tenancy

  # Tenant context
  tenant_id: production-tenant

  # Enable advanced features
  features:
    anomaly_detection: true
    chaos_mesh_integration: true
    plugin_execution: true
    time_travel: true

  # Complex step orchestration
  steps:
    # Step 1: Baseline measurement
    - name: collect_baseline
      type: custom
      plugin: metrics-collector
      config:
        duration: 5m
        metrics:
          - response_time_ms
          - error_rate
          - request_throughput

    # Step 2: Time travel setup
    - name: setup_time_travel
      type: time_travel
      config:
        enabled: true
        initial_time: "2024-01-01T00:00:00Z"

    # Step 3: Chaos Mesh pod kill
    - name: pod_chaos
      type: chaos_mesh
      experiment: pod-kill-test
      wait_for_completion: true
      depends_on: ["collect_baseline"]

    # Step 4: Monitor for anomalies
    - name: detect_anomalies
      type: ml_detection
      metrics:
        - response_time_ms
        - error_rate
      alert_threshold: high
      depends_on: ["pod_chaos"]

    # Step 5: Custom fault injection
    - name: database_fault
      type: plugin
      plugin: database-fault-injector
      config:
        fault_type: slow_query
        latency_ms: 1000
        duration: 2m
      depends_on: ["detect_anomalies"]

    # Step 6: Network chaos
    - name: network_latency
      type: chaos_mesh
      experiment: network-latency-test
      depends_on: ["database_fault"]

    # Step 7: Final analysis
    - name: analyze_results
      type: custom
      plugin: prometheus-exporter
      config:
        export_metrics: true
        generate_report: true
      depends_on: ["network_latency"]

  # Conditional execution
  conditions:
    - name: high_load_detected
      expression: "metrics.request_throughput > 1000"
      actions:
        - skip_step: "network_latency"
        - enable_step: "load_shedding"

    - name: anomaly_critical
      expression: "anomaly.severity == 'critical'"
      actions:
        - abort_orchestration: true
        - send_alert: "critical_anomaly"

  # Assertions and validations
  assertions:
    - metric: response_time_ms
      operator: less_than
      value: 1000
      severity: high

    - metric: error_rate
      operator: less_than
      value: 0.05
      severity: critical

    - metric: anomaly_count
      operator: equals
      value: 0
      severity: medium

  # Cleanup configuration
  cleanup:
    - delete_chaos_mesh_experiments: true
    - export_metrics: true
    - send_notifications: true
    - reset_time_travel: true

Observability Integration

Advanced observability with Prometheus, OpenTelemetry, and alerting.

Prometheus Integration

# mockforge.yaml
observability:
  prometheus:
    enabled: true
    port: 9090
    path: /metrics

    # Custom metrics
    custom_metrics:
      - name: mockforge_scenario_duration
        type: histogram
        description: "Time spent executing scenarios"
        labels: ["scenario_name", "tenant_id"]

      - name: mockforge_anomaly_detected
        type: counter
        description: "Number of anomalies detected"
        labels: ["severity", "metric_name"]

  opentelemetry:
    enabled: true
    endpoint: http://otel-collector:4317

    # Tracing configuration
    tracing:
      service_name: mockforge
      service_version: "1.0.0"
      sample_rate: 0.1

    # Metrics configuration
    metrics:
      export_interval: 30s
      resource_attributes:
        service.name: mockforge
        service.version: "1.0.0"

Alerting Configuration

observability:
  alerts:
    - name: anomaly_detected
      condition: "anomaly.severity >= 'high'"
      channels:
        - slack
        - email
        - webhook
      cooldown: 5m

    - name: quota_exceeded
      condition: "tenant.usage >= tenant.quota * 0.9"
      channels:
        - email
      cooldown: 1h

    - name: service_degradation
      condition: "metrics.response_time_p95 > 2000"
      channels:
        - slack
        - pager_duty
      cooldown: 10m

  # Alert channels configuration
  channels:
    slack:
      webhook_url: "${SLACK_WEBHOOK_URL}"
      channel: "#alerts"
      username: "MockForge Alert"

    email:
      smtp_server: "smtp.company.com"
      smtp_port: 587
      username: "${SMTP_USERNAME}"
      password: "${SMTP_PASSWORD}"
      from: "[email protected]"
      to: ["[email protected]", "[email protected]"]

    webhook:
      url: "https://alert-manager.company.com/webhook"
      headers:
        Authorization: "Bearer ${WEBHOOK_TOKEN}"
      method: POST

Security and Encryption

Advanced security features for enterprise deployments.

Encryption Configuration

# mockforge.yaml
security:
  encryption:
    enabled: true

    # Key management
    keys:
      default:
        algorithm: AES-256-GCM
        key_rotation_days: 30

      sensitive:
        algorithm: AES-256-GCM
        hsm_integration: true

    # Data encryption
    data_encryption:
      fixtures: true
      logs: true
      configuration: false

    # TLS configuration
    tls:
      enabled: true
      certificate_file: /etc/ssl/mockforge.crt
      private_key_file: /etc/ssl/mockforge.key
      client_auth: optional

Authentication and Authorization

security:
  auth:
    # JWT configuration
    jwt:
      enabled: true
      secret: "${JWT_SECRET}"
      issuer: "mockforge"
      audience: "mockforge-users"
      algorithms: ["HS256", "RS256"]

    # OAuth2 integration
    oauth2:
      enabled: true
      provider: keycloak
      client_id: "${OAUTH2_CLIENT_ID}"
      client_secret: "${OAUTH2_CLIENT_SECRET}"
      token_url: "https://auth.company.com/token"
      userinfo_url: "https://auth.company.com/userinfo"

    # Role-based access control
    rbac:
      enabled: true
      roles:
        admin:
          permissions:
            - "scenarios:*"
            - "tenants:*"
            - "system:*"

        developer:
          permissions:
            - "scenarios:read"
            - "scenarios:execute"
            - "fixtures:*"

        viewer:
          permissions:
            - "scenarios:read"
            - "fixtures:read"
            - "metrics:read"

Performance Tuning

Advanced performance configuration for high-throughput scenarios.

Resource Limits

# mockforge.yaml
performance:
  # Thread pool configuration
  thread_pool:
    http_workers: 16
    background_workers: 4
    max_blocking_threads: 512

  # Memory management
  memory:
    max_heap_size_mb: 2048
    gc_threshold_mb: 1024
    cache_size_mb: 512

  # Connection pooling
  connections:
    max_http_connections: 1000
    connection_timeout_secs: 30
    keep_alive_secs: 300

  # Request processing
  requests:
    max_concurrent_requests: 10000
    request_timeout_secs: 60
    buffer_size_kb: 64

Caching Configuration

performance:
  caching:
    # Response caching
    responses:
      enabled: true
      max_size_mb: 100
      ttl_secs: 300
      compression: true

    # Template caching
    templates:
      enabled: true
      max_entries: 1000
      ttl_secs: 3600

    # Plugin caching
    plugins:
      enabled: true
      max_instances: 10
      preload: ["metrics-collector", "template-renderer"]

Monitoring and Profiling

performance:
  monitoring:
    # Performance metrics
    metrics:
      enabled: true
      interval_secs: 30
      export_format: prometheus

    # Profiling
    profiling:
      enabled: true
      sample_rate: 1000  # 1000 Hz
      max_stack_depth: 64

    # Health checks
    health_checks:
      enabled: true
      interval_secs: 60
      failure_threshold: 3

Environment Variables

Most advanced features are YAML-configured rather than env-var-driven — the env-var surface is intentionally narrow (see Environment Variables for the canonical list). For toggles you’d want to flip per-deployment, point --config <path> at a deployment-specific YAML file rather than relying on dozens of MOCKFORGE_*_ENABLED flags.

The cross-cutting feature toggles that DO have env vars:

# Core feature flags
MOCKFORGE_LATENCY_ENABLED=true
MOCKFORGE_FAILURES_ENABLED=true
MOCKFORGE_RATE_LIMIT_ENABLED=true

# Persistent metrics record (CSV)
MOCKFORGE_METRICS_LOG_FILE=/var/log/mockforge.csv

# Distributed tracing
MOCKFORGE_OTLP_ENDPOINT=http://collector:4317
MOCKFORGE_OTLP_SAMPLING_RATE=1.0

Everything else lives in YAML.

Best Practices

Configuration Management

  1. Version Control: Keep all configuration files in version control
  2. Environment Separation: Use different configurations for dev/staging/prod
  3. Secrets Management: Never commit secrets to version control
  4. Validation: Always validate configurations before deployment

Security

  1. Principle of Least Privilege: Grant minimal required permissions
  2. Network Security: Use firewalls and network policies
  3. Audit Logging: Enable comprehensive audit logging
  4. Regular Updates: Keep MockForge and dependencies updated

Performance

  1. Resource Monitoring: Monitor resource usage continuously
  2. Load Testing: Test configurations under load
  3. Caching Strategy: Configure appropriate caching for your use case
  4. Scalability Planning: Plan for growth and scale accordingly

Troubleshooting

  1. Debug Logging: Enable debug logging for troubleshooting
  2. Metrics Collection: Use observability tools for monitoring
  3. Configuration Validation: Validate configurations regularly
  4. Incremental Changes: Make configuration changes incrementally

This comprehensive guide covers MockForge’s advanced configuration options for enterprise-grade API mocking and chaos engineering scenarios.

Building from Source

This guide covers building MockForge from source code, including prerequisites, build processes, and troubleshooting common build issues.

Prerequisites

Before building MockForge, ensure you have the required development tools installed.

System Requirements

  • Rust: Version 1.70.0 or later
  • Cargo: Included with Rust
  • Git: For cloning the repository
  • C/C++ Compiler: For native dependencies

Platform-Specific Requirements

Linux (Ubuntu/Debian)

# Install build essentials
sudo apt update
sudo apt install build-essential pkg-config libssl-dev

# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

macOS

# Install Xcode command line tools
xcode-select --install

# Install Homebrew (optional, for additional tools)
# /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Windows

# Install Visual Studio Build Tools
# Download from: https://visualstudio.microsoft.com/visual-cpp-build-tools/

# Install Rust
# Download from: https://rustup.rs/
# Or use winget: winget install --id Rustlang.Rustup

Rust Setup Verification

# Verify Rust installation
rustc --version
cargo --version

# Update to latest stable
rustup update stable

Cloning the Repository

# Clone the repository
git clone https://github.com/SaaSy-Solutions/mockforge.git
cd mockforge

# Initialize submodules (if any)
git submodule update --init --recursive

Build Process

Basic Build

# Build all crates in debug mode (default)
cargo build

# Build in release mode for production
cargo build --release

# Build specific crate
cargo build -p mockforge-cli

Build Outputs

After building, binaries are available in:

# Debug builds
target/debug/mockforge-cli

# Release builds
target/release/mockforge-cli

Build Features

MockForge supports conditional compilation features:

# Build with all features enabled
cargo build --all-features

# Build with specific features
cargo build --features "grpc,websocket"

# List available features
cargo metadata --format-version 1 | jq '.packages[] | select(.name == "mockforge-cli") | .features'

Development Workflow

Development Builds

# Quick development builds
cargo build

# Run tests during development
cargo test

# Run specific tests
cargo test --package mockforge-core --lib

Watch Mode Development

# Install cargo-watch for automatic rebuilds
cargo install cargo-watch

# Watch for changes and rebuild
cargo watch -x build

# Watch and run tests
cargo watch -x test

# Watch and run specific binary
cargo watch -x "run --bin mockforge-cli -- --help"

IDE Setup

VS Code

Install recommended extensions:

  • rust-lang.rust-analyzer
  • ms-vscode.vscode-json
  • redhat.vscode-yaml

IntelliJ/CLion

Install Rust plugin through marketplace.

Debugging

# Build with debug symbols
cargo build

# Run with debugger
rust-gdb target/debug/mockforge-cli

# Or use lldb on macOS
rust-lldb target/debug/mockforge-cli

Advanced Build Options

Cross-Compilation

# Install cross-compilation targets
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-gnu

# Build for different architectures
cargo build --target x86_64-unknown-linux-musl
cargo build --target aarch64-unknown-linux-gnu

Custom Linker

# Use mold linker for faster linking (Linux)
sudo apt install mold
export RUSTFLAGS="-C link-arg=-fuse-ld=mold"
cargo build

Build Caching

# Use sccache for faster rebuilds
cargo install sccache
export RUSTC_WRAPPER=sccache
cargo build

Testing

Running Tests

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test
cargo test test_name

# Run tests for specific package
cargo test -p mockforge-core

# Run integration tests
cargo test --test integration

# Run with release optimizations
cargo test --release

Test Coverage

# Install cargo-tarpaulin
cargo install cargo-tarpaulin

# Generate coverage report
cargo tarpaulin --out Html

# Open coverage report
open tarpaulin-report.html

Benchmarking

# Run benchmarks
cargo bench

# Run specific benchmark
cargo bench benchmark_name

Code Quality

Linting

# Run clippy lints
cargo clippy

# Run with pedantic mode
cargo clippy -- -W clippy::pedantic

# Auto-fix some issues
cargo clippy --fix

Formatting

# Check code formatting
cargo fmt --check

# Auto-format code
cargo fmt

Security Auditing

# Install cargo-audit
cargo install cargo-audit

# Audit dependencies for security vulnerabilities
cargo audit

Documentation

Building Documentation

# Build API documentation
cargo doc

# Open documentation in browser
cargo doc --open

# Build documentation with private items
cargo doc --document-private-items

# Build for specific package
cargo doc -p mockforge-core

Building mdBook

# Install mdbook
cargo install mdbook

# Build the documentation
mdbook build

# Serve documentation locally
mdbook serve

Packaging and Distribution

Creating Releases

# Create a release build
cargo build --release

# Strip debug symbols (Linux/macOS)
strip target/release/mockforge-cli

# Create distribution archive
tar -czf mockforge-v0.1.0-x86_64-linux.tar.gz \
  -C target/release mockforge-cli

# Create Debian package
cargo install cargo-deb
cargo deb

Docker Builds

# Build Docker image
docker build -t mockforge .

# Build with buildkit for faster builds
DOCKER_BUILDKIT=1 docker build -t mockforge .

# Multi-stage build for smaller images
docker build -f Dockerfile.multi-stage -t mockforge .

Troubleshooting Build Issues

Common Problems

Compilation Errors

Problem: error[E0432]: unresolved import

Solution: Check that dependencies are properly specified in Cargo.toml

# Update dependencies
cargo update

# Clean and rebuild
cargo clean
cargo build

Linker Errors

Problem: undefined reference to...

Solution: Install system dependencies

# Ubuntu/Debian
sudo apt install libssl-dev pkg-config

# macOS
brew install openssl pkg-config

Out of Memory

Problem: fatal error: Killed signal terminated program cc1

Solution: Increase available memory or reduce parallelism

# Reduce parallel jobs
cargo build --jobs 1

# Or set memory limits
export CARGO_BUILD_JOBS=2

Slow Builds

Solutions:

# Use incremental compilation
export CARGO_INCREMENTAL=1

# Use faster linker
export RUSTFLAGS="-C link-arg=-fuse-ld=mold"

# Use build cache
cargo install sccache
export RUSTC_WRAPPER=sccache

Platform-Specific Issues

Windows

# Install Windows SDK if missing
# Download from: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/

# Use different target for static linking
cargo build --target x86_64-pc-windows-msvc

macOS

# Install missing headers
open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

# Or reinstall command line tools
sudo rm -rf /Library/Developer/CommandLineTools
xcode-select --install

Linux

# Install additional development libraries
sudo apt install libclang-dev llvm-dev

# For cross-compilation
sudo apt install gcc-aarch64-linux-gnu

Network Issues

# Clear cargo cache
cargo clean
rm -rf ~/.cargo/registry/cache
rm -rf ~/.cargo/git/checkouts

# Use different registry
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse

Dependency Conflicts

# Update Cargo.lock
cargo update

# Resolve conflicts
cargo update -p package-name

# Use cargo-tree to visualize dependencies
cargo install cargo-tree
cargo tree

Performance Optimization

Release Builds

# Optimized release build
cargo build --release

# With Link-Time Optimization (LTO)
export RUSTFLAGS="-C opt-level=3 -C lto=fat -C codegen-units=1"
cargo build --release

Profile-Guided Optimization (PGO)

# Build with instrumentation
export RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data"
cargo build --release

# Run instrumented binary with representative workload
./target/release/mockforge-cli serve --spec examples/openapi-demo.json &
sleep 10
curl -s http://localhost:3000/users > /dev/null
pkill mockforge-cli

# Build optimized version
export RUSTFLAGS="-Cprofile-use=/tmp/pgo-data"
cargo build --release

Contributing to the Build System

Adding New Dependencies

# Add to workspace Cargo.toml
[workspace.dependencies]
new-dependency = "1.0"

# Use in crate Cargo.toml
[dependencies]
new-dependency = { workspace = true }

Adding Build Scripts

// build.rs
fn main() {
    // Generate code or check dependencies
    println!("cargo:rerun-if-changed=proto/");
    tonic_build::compile_protos("proto/service.proto").unwrap();
}

Custom Build Profiles

# In Cargo.toml
[profile.release]
opt-level = 3
lto = true
codegen-units = 1
panic = "abort"

[profile.dev]
opt-level = 0
debug = true
overflow-checks = true

This comprehensive build guide ensures developers can successfully compile, test, and contribute to MockForge across different platforms and development environments.

Testing Guide

This guide covers MockForge’s comprehensive testing strategy, including unit tests, integration tests, end-to-end tests, and testing best practices.

Testing Overview

MockForge employs a multi-layered testing approach to ensure code quality and prevent regressions:

  • Unit Tests: Individual functions and modules
  • Integration Tests: Component interactions
  • End-to-End Tests: Full system workflows
  • Performance Tests: Load and performance validation
  • Security Tests: Vulnerability and access control testing

Unit Testing

Running Unit Tests

# Run all unit tests
cargo test --lib

# Run tests for specific crate
cargo test -p mockforge-core

# Run specific test function
cargo test test_template_rendering

# Run tests matching pattern
cargo test template

# Run tests with output
cargo test -- --nocapture

Writing Unit Tests

Basic Test Structure

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_functionality() {
        // Arrange
        let input = "test input";
        let expected = "expected output";

        // Act
        let result = process_input(input);

        // Assert
        assert_eq!(result, expected);
    }

    #[test]
    fn test_error_conditions() {
        // Test error cases
        let result = process_input("");
        assert!(result.is_err());
    }
}
}

Async Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod async_tests {
    use tokio::test;

    #[tokio::test]
    async fn test_async_operation() {
        let result = async_operation().await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_concurrent_operations() {
        let (result1, result2) = tokio::join(
            async_operation(),
            another_async_operation()
        );

        assert!(result1.is_ok());
        assert!(result2.is_ok());
    }
}
}

Integration Testing

Component Integration Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod integration_tests {
    use mockforge_core::config::MockForgeConfig;
    use mockforge_http::HttpServer;

    #[tokio::test]
    async fn test_http_server_integration() {
        // Start test server
        let config = test_config();
        let server = HttpServer::new(config);
        let addr = server.local_addr();

        tokio::spawn(async move {
            server.serve().await.unwrap();
        });

        // Wait for server to start
        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

        // Test HTTP request
        let client = reqwest::Client::new();
        let response = client
            .get(&format!("http://{}/health", addr))
            .send()
            .await
            .unwrap();

        assert_eq!(response.status(), 200);
    }
}
}

End-to-End Testing

Full System Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod e2e_tests {
    use std::process::Command;
    use std::thread;
    use std::time::Duration;

    #[test]
    fn test_full_openapi_workflow() {
        // Start MockForge server
        let mut server = Command::new("cargo")
            .args(&["run", "--bin", "mockforge-cli", "serve",
                   "--spec", "examples/openapi-demo.json",
                   "--http-port", "3000"])
            .spawn()
            .unwrap();

        // Wait for server to start
        thread::sleep(Duration::from_secs(2));

        // Test API endpoints
        test_user_endpoints();
        test_product_endpoints();

        // Stop server
        server.kill().unwrap();
    }
}
}

Performance Testing

Load Testing

# Using hey for HTTP load testing
hey -n 1000 -c 10 http://localhost:3000/users

# Using work for more detailed benchmarking
work -t 4 -c 100 -d 30s http://localhost:3000/users

Benchmarking

#![allow(unused)]
fn main() {
// In benches/benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn benchmark_template_rendering(c: &mut Criterion) {
    let engine = TemplateEngine::new();

    c.bench_function("template_render_simple", |b| {
        b.iter(|| {
            engine.render("Hello {{name}}", &Context::from_value("name", "World"))
        })
    });
}

criterion_group!(benches, benchmark_template_rendering);
criterion_main!(benches);
}

Run benchmarks:

cargo bench

Security Testing

Input Validation Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod security_tests {
    #[test]
    fn test_sql_injection_prevention() {
        let input = "'; DROP TABLE users; --";
        let result = sanitize_input(input);

        // Ensure dangerous characters are escaped
        assert!(!result.contains("DROP"));
    }

    #[test]
    fn test_template_injection() {
        let engine = TemplateEngine::new();
        let malicious = "{{#exec}}rm -rf /{{/exec}}";

        // Should not execute dangerous commands
        let result = engine.render(malicious, &Context::new());
        assert!(!result.contains("exec"));
    }
}
}

Continuous Integration

GitHub Actions Testing

# .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - uses: actions-rs/toolchain@v1
      with:
        toolchain: stable
        override: true

    - name: Cache dependencies
      uses: actions/cache@v2
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

    - name: Run tests
      run: cargo test --verbose

    - name: Run clippy
      run: cargo clippy -- -D warnings

    - name: Check formatting
      run: cargo fmt --check

    - name: Run security audit
      run: cargo audit

This comprehensive testing guide ensures MockForge maintains high code quality and prevents regressions across all components and integration points.

Architecture Overview

MockForge is a modular, Rust-based platform for mocking APIs across HTTP, WebSocket, and gRPC protocols. This document provides a comprehensive overview of the system architecture, design principles, and component interactions.

System Overview

MockForge enables frontend and integration development without live backends by providing realistic API mocking with configurable latency, failure injection, and dynamic response generation. The system is built as a modular workspace of Rust crates that share a core engine for request routing, validation, and data generation.

Key Design Principles

  • Modularity: Separated concerns across focused crates
  • Extensibility: Plugin architecture for custom functionality
  • Performance: Async-first design with efficient resource usage
  • Developer Experience: Comprehensive tooling and clear APIs
  • Protocol Agnostic: Unified approach across different protocols

High-Level Architecture

graph TB
    subgraph "User Interfaces"
        CLI[CLI mockforge-cli]
        UI[Admin UI v2]
    end

    subgraph "Core Engine"
        Router[Route Registry]
        Templates[Template Engine]
        Validator[Schema Validator]
        Latency[Latency Injector]
        Failure[Failure Injector]
        Logger[Request Logger]
        Plugins[Plugin System]
    end

    subgraph "Protocol Handlers"
        HTTP[HTTP Server<br/>axum]
        WS[WebSocket Server<br/>tokio-ws]
        GRPC[gRPC Server<br/>tonic]
    end

    subgraph "Data Layer"
        DataGen[Data Generator<br/>faker + RAG]
        Workspace[Workspace Manager]
        Encryption[Encryption Engine]
    end

    CLI --> Router
    UI --> Router

    Router --> HTTP
    Router --> WS
    Router --> GRPC

    HTTP --> Templates
    WS --> Templates
    GRPC --> Templates

    Templates --> Validator
    Validator --> Latency
    Latency --> Failure
    Failure --> Logger

    Templates --> DataGen
    Templates --> Plugins

    Router --> Workspace
    Workspace --> Encryption

    style CLI fill:#e1f5ff
    style UI fill:#e1f5ff
    style Router fill:#ffe1e1
    style Templates fill:#ffe1e1
    style DataGen fill:#e1ffe1

Crate Structure

MockForge is organized as a Cargo workspace with 56 crates grouped by concern. The current authoritative list is in the root Cargo.toml’s [workspace.members]; the table below summarizes the major groupings.

Foundation

CratePurpose
mockforge-foundationShared error types, encryption primitives
mockforge-coreServer, routing, OpenAPI parsing, middleware
mockforge-configConfiguration types and loading
mockforge-security-coreAuth/security primitives
mockforge-template-expansionHandlebars rendering
mockforge-dataData models, synthesis, RAG
mockforge-world-stateStateful mock behavior
mockforge-scenariosTest scenario management

Protocol implementations

CratePurpose
mockforge-httpHTTP REST (primary protocol)
mockforge-grpcgRPC services
mockforge-wsWebSocket connections
mockforge-graphqlGraphQL
mockforge-kafkaKafka event streaming
mockforge-mqttMQTT pub/sub
mockforge-amqpAMQP message queuing
mockforge-smtpSMTP email
mockforge-ftpFTP
mockforge-tcpRaw TCP

Plugin & extension layer

CratePurpose
mockforge-plugin-corePlugin trait definitions
mockforge-plugin-sdkSDK for plugin authors
mockforge-plugin-loaderWASM dynamic loading
mockforge-plugin-cliPlugin management CLI
mockforge-plugin-registryLocal plugin registry
mockforge-registry-serverMulti-tenant marketplace API
mockforge-registry-coreShared registry types

Bench, test & observability

CratePurpose
mockforge-benchk6 generation, OWASP testing, native chunked bench
mockforge-chaosChaos engineering (latency, faults, TCP-level errors)
mockforge-chaos-orchestrationMulti-step chaos scenarios
mockforge-chaos-mlML-driven chaos analysis
mockforge-route-chaosPer-route chaos injection
mockforge-recorderTraffic recording
mockforge-testTest framework utilities
mockforge-observabilityMetrics, OTLP, dashboards
mockforge-tracingDistributed tracing
mockforge-analyticsUsage analytics
mockforge-reportingReport generation
mockforge-performancePerformance profiling
mockforge-pipelinesRequest/response pipelines

User-facing

CratePurpose
mockforge-cliMain mockforge binary
mockforge-uiReact admin UI (Vite + React 19)
mockforge-tuiTerminal UI dashboard
mockforge-sdkClient SDK

Infrastructure / extension

CratePurpose
mockforge-proxyPass-through / record-replay proxy
mockforge-tunnelTunnel support
mockforge-vbrVirtual branch resilience
mockforge-collabCollaborative features (SQLite/SQLx)
mockforge-federationCross-instance federation
mockforge-k8s-operatorKubernetes operator
mockforge-runtime-daemonRuntime daemon
mockforge-importSpec import (HAR, Postman, etc.)
mockforge-intelligenceAI-driven mocking
mockforge-ai-coreAI primitives
mockforge-behavioral-cloningRecord real traffic, replay synthetically
mockforge-contractsContract testing
mockforge-openapiOpenAPI types and helpers
mockforge-workspaceWorkspace persistence

Crate Responsibilities

mockforge-core - Shared Core Engine

The foundation crate providing common functionality used across all protocols:

  • Request Routing: Unified route registry and matching logic
  • Validation Engine: OpenAPI and schema validation
  • Template System: Handlebars-based dynamic content generation
  • Latency Injection: Configurable response delays
  • Failure Injection: Simulated error conditions
  • Record/Replay: Request/response capture and replay
  • Logging: Structured request/response logging
  • Configuration: Unified configuration management

mockforge-http - HTTP REST API Mocking

HTTP-specific implementation built on axum:

  • OpenAPI Integration: Automatic route generation from specifications
  • Request Matching: Method, path, query, header, and body matching
  • Response Generation: Schema-driven and template-based responses
  • Middleware Support: Custom request/response processing

mockforge-ws - WebSocket Connection Mocking

Real-time communication mocking:

  • Replay Mode: Scripted message sequences with timing control
  • Interactive Mode: Dynamic responses based on client messages
  • State Management: Connection-specific state tracking
  • Template Support: Dynamic message content generation

mockforge-grpc - gRPC Service Mocking

Protocol buffer-based service mocking:

  • Dynamic Proto Discovery: Automatic compilation of .proto files
  • Service Reflection: Runtime service discovery and inspection
  • Streaming Support: Unary, server, client, and bidirectional streaming
  • Schema Validation: Message validation against proto definitions

mockforge-data - Synthetic Data Generation

Advanced data generation capabilities:

  • Faker Integration: Realistic fake data generation
  • RAG Enhancement: Retrieval-augmented generation for contextual data
  • Schema-Driven Generation: Data conforming to JSON Schema/OpenAPI specs
  • Template Helpers: Integration with core templating system

mockforge-cli - Command-Line Interface

User-facing command-line tool:

  • Server Management: Start/stop mock servers
  • Configuration: Load and validate configuration files
  • Data Generation: Command-line data generation utilities
  • Development Tools: Testing and debugging utilities

mockforge-ui - Admin Web Interface

Browser-based management interface:

  • Real-time Monitoring: Live request/response viewing
  • Configuration Management: Runtime configuration changes
  • Fixture Management: Recorded interaction management
  • Performance Metrics: Response times and error rates

Core Engine Architecture

Request Processing Pipeline

All requests follow a unified processing pipeline regardless of protocol:

  1. Request Reception: Protocol-specific server receives request
  2. Route Matching: Core routing engine matches request to handler
  3. Validation: Schema validation if enabled
  4. Template Processing: Dynamic content generation
  5. Latency Injection: Artificial delays if configured
  6. Failure Injection: Error simulation if enabled
  7. Response Generation: Handler generates response
  8. Logging: Request/response logging
  9. Response Delivery: Protocol-specific response sending
sequenceDiagram
    participant Client
    participant Server as Protocol Server<br/>(HTTP/WS/gRPC)
    participant Router as Route Registry
    participant Validator
    participant Templates
    participant Latency
    participant Failure
    participant Handler
    participant Logger

    Client->>Server: Incoming Request
    Server->>Router: Match Route
    Router->>Router: Find Handler

    alt Route Found
        Router->>Validator: Validate Request

        alt Validation Enabled
            Validator->>Validator: Check Schema
            alt Valid
                Validator->>Templates: Process Request
            else Invalid
                Validator-->>Server: Validation Error
                Server-->>Client: 400 Bad Request
            end
        else Validation Disabled
            Validator->>Templates: Process Request
        end

        Templates->>Templates: Render Template
        Templates->>Handler: Generate Response
        Handler->>Latency: Apply Delays
        Latency->>Failure: Check Failure Rules

        alt Should Fail
            Failure-->>Server: Simulated Error
            Server-->>Client: Error Response
        else Success
            Failure->>Logger: Log Request/Response
            Logger-->>Server: Response Data
            Server-->>Client: Success Response
        end
    else Route Not Found
        Router-->>Server: No Match
        Server-->>Client: 404 Not Found
    end

Route Registry System

The core routing system provides unified route management:

#![allow(unused)]
fn main() {
pub struct RouteRegistry {
    routes: HashMap<RouteKey, Vec<RouteHandler>>,
    overrides: Overrides,
    validation_mode: ValidationMode,
}

impl RouteRegistry {
    pub fn register(&mut self, key: RouteKey, handler: RouteHandler);
    pub fn match_route(&self, request: &Request) -> Option<&RouteHandler>;
    pub fn apply_overrides(&mut self, overrides: &Overrides);
}
}

Template Engine

Handlebars-based templating with custom helpers:

#![allow(unused)]
fn main() {
pub struct TemplateEngine {
    registry: handlebars::Handlebars<'static>,
}

impl TemplateEngine {
    pub fn render(&self, template: &str, context: &Context) -> Result<String>;
    pub fn register_helper(&mut self, name: &str, helper: Box<dyn HelperDef>);
}
}

Built-in helpers include:

  • uuid: Generate unique identifiers
  • now: Current timestamp
  • randInt: Random integers
  • request: Access request data
  • faker: Synthetic data generation

Plugin System Architecture

MockForge uses a WebAssembly-based plugin system for extensibility:

graph TB
    subgraph "Plugin Lifecycle"
        Load[Load Plugin WASM]
        Init[Initialize Plugin]
        Register[Register Hooks]
        Execute[Execute Plugin]
        Cleanup[Cleanup Resources]
    end

    subgraph "Plugin Types"
        Auth[Authentication<br/>JWT, OAuth2, etc.]
        Response[Response Generators<br/>GraphQL, Custom Data]
        DataSource[Data Sources<br/>CSV, Database, API]
        Template[Template Extensions<br/>Custom Functions]
    end

    subgraph "Security Sandbox"
        Isolate[WASM Isolation]
        Limits[Resource Limits<br/>Memory, CPU, Time]
        Perms[Permission System]
    end

    subgraph "Core Integration"
        Loader[Plugin Loader]
        Registry[Plugin Registry]
        API[Plugin API]
    end

    Load --> Init
    Init --> Register
    Register --> Execute
    Execute --> Cleanup

    Auth --> Loader
    Response --> Loader
    DataSource --> Loader
    Template --> Loader

    Loader --> Registry
    Registry --> API

    API --> Isolate
    Isolate --> Limits
    Limits --> Perms

    style Auth fill:#e1f5ff
    style Response fill:#e1f5ff
    style DataSource fill:#e1f5ff
    style Template fill:#e1f5ff
    style Isolate fill:#ffe1e1
    style Limits fill:#ffe1e1
    style Perms fill:#ffe1e1

Plugin Hook Points:

  1. Request Interceptors: Modify incoming requests
  2. Response Generators: Create custom response data
  3. Template Helpers: Add custom template functions
  4. Authentication Providers: Implement auth schemes
  5. Data Source Connectors: Connect to external data sources

Security Model:

  • WASM sandboxing isolates plugin execution
  • Resource limits prevent DoS attacks
  • Permission system controls plugin capabilities
  • Plugin signature verification (planned)

This architecture provides a solid foundation for API mocking while maintaining extensibility, performance, and developer experience. The modular design allows for independent evolution of each protocol implementation while sharing common infrastructure.

CLI Crate

The mockforge-cli crate provides the primary command-line interface for MockForge, serving as the main entry point for users to interact with the MockForge ecosystem. It orchestrates all MockForge services and provides comprehensive configuration and management capabilities.

Architecture Overview

graph TD
    A[CLI Entry Point] --> B[Command Parser]
    B --> C{Command Type}
    C --> D[Serve Command]
    C --> E[Plugin Commands]
    C --> F[Workspace Commands]
    C --> G[Data Commands]
    C --> H[Other Commands]

    D --> I[Server Orchestration]
    I --> J[HTTP Server]
    I --> K[WebSocket Server]
    I --> L[gRPC Server]
    I --> M[SMTP Server]
    I --> N[Admin UI]
    I --> O[Metrics Server]

Core Components

Command Structure

The CLI uses clap for argument parsing and command structure. The main Cli struct defines the top-level interface with global options and subcommands.

Main Commands

  • serve: Start MockForge servers (HTTP, WebSocket, gRPC, SMTP)
  • admin: Start standalone admin UI server
  • sync: Bidirectional workspace synchronization daemon
  • plugin: Plugin management (install, uninstall, update, list)
  • workspace: Multi-tenant workspace management
  • data: Synthetic data generation
  • generate-tests: Test generation from recorded API interactions
  • suggest: AI-powered API specification suggestions
  • bench: Load testing against real services
  • orchestrate: Chaos experiment orchestration

Server Orchestration

The serve command is the most complex, supporting extensive configuration options:

Server Types

  • HTTP Server: REST API mocking with OpenAPI support
  • WebSocket Server: Real-time messaging simulation
  • gRPC Server: Protocol buffer-based service mocking
  • SMTP Server: Email service simulation
  • Admin UI: Web-based management interface
  • Metrics Server: Prometheus metrics endpoint

Configuration Layers

The CLI implements a three-tier configuration precedence system:

  1. CLI Arguments: Highest precedence, command-line flags
  2. Configuration File: YAML/JSON config file (optional)
  3. Environment Variables: Lowest precedence, environment overrides

Advanced Features

  • Chaos Engineering: Fault injection, latency simulation, network degradation
  • Traffic Shaping: Bandwidth limiting, packet loss simulation
  • Observability: OpenTelemetry tracing, Prometheus metrics, API flight recording
  • AI Integration: RAG-powered intelligent mocking
  • Multi-tenancy: Workspace isolation and management

Key Modules

main.rs

The main entry point that:

  • Parses CLI arguments using clap
  • Initializes logging and observability
  • Routes commands to appropriate handlers
  • Manages server lifecycle and graceful shutdown

plugin_commands.rs

Handles plugin ecosystem management:

  • Plugin installation from various sources (URLs, Git repos, local paths)
  • Plugin validation and security verification
  • Cache management for downloaded plugins
  • Registry integration (future feature)

workspace_commands.rs

Multi-tenant workspace management:

  • CRUD operations for workspaces
  • Workspace statistics and monitoring
  • Enable/disable workspace functionality
  • REST API integration with admin UI

Import Modules

  • curl_import.rs: Convert curl commands to MockForge configurations
  • postman_import.rs: Import Postman collections
  • insomnia_import.rs: Import Insomnia workspaces
  • import_utils.rs: Shared utilities for import operations

Configuration Management

Server Configuration Building

The build_server_config_from_cli() function merges configuration from multiple sources:

#![allow(unused)]
fn main() {
// Step 1: Load config from file if provided
let mut config = load_config_with_fallback(path)?;

// Step 2: Apply environment variable overrides
config = apply_env_overrides(config);

// Step 3: Apply CLI argument overrides (highest precedence)
config.http.port = serve_args.http_port;
// ... more overrides
}

Validation

Before starting servers, the CLI performs comprehensive validation:

  • Configuration file existence and readability
  • OpenAPI spec file validation
  • Port availability checking
  • Dry-run mode for configuration testing

Server Lifecycle Management

Concurrent Server Startup

All servers are started concurrently using Tokio tasks:

#![allow(unused)]
fn main() {
// Start HTTP server
let http_handle = tokio::spawn(async move {
    mockforge_http::serve_router(http_port, http_app)
});

// Start WebSocket server
let ws_handle = tokio::spawn(async move {
    mockforge_ws::start_with_latency(ws_port, None)
});

// Start gRPC server
let grpc_handle = tokio::spawn(async move {
    mockforge_grpc::start(grpc_port)
});
}

Graceful Shutdown

The CLI implements graceful shutdown using Tokio’s CancellationToken:

#![allow(unused)]
fn main() {
let shutdown_token = CancellationToken::new();

// All servers listen for cancellation
tokio::select! {
    result = server_task => { /* handle result */ }
    _ = shutdown_token.cancelled() => { /* cleanup */ }
}
}

Integration Points

Core Crate Dependencies

The CLI depends on all MockForge service crates:

  • mockforge-core: Configuration and shared utilities
  • mockforge-http: HTTP server implementation
  • mockforge-ws: WebSocket server
  • mockforge-grpc: gRPC server
  • mockforge-smtp: SMTP server
  • mockforge-ui: Admin interface
  • mockforge-observability: Metrics and tracing
  • mockforge-data: Data generation and RAG
  • mockforge-plugin-*: Plugin ecosystem

External Integrations

  • OpenTelemetry: Distributed tracing
  • Prometheus: Metrics collection
  • Jaeger: Trace visualization
  • Plugin Registry: Remote plugin distribution
  • AI Providers: OpenAI, Anthropic, Ollama for intelligent features

Error Handling

The CLI implements comprehensive error handling:

  • User-friendly error messages with suggestions
  • Validation errors with specific guidance
  • Network error recovery and retry logic
  • Graceful degradation when services fail

Testing

The CLI includes integration tests in tests/cli_integration_tests.rs and configuration validation tests in tests/config_validation_tests.rs, ensuring reliability of the command-line interface and configuration parsing.

Future Enhancements

  • Plugin Marketplace: Integrated plugin discovery and installation
  • Interactive Mode: Shell-like interface for complex workflows
  • Configuration Wizards: Guided setup for new users
  • Remote Management: Cloud-based MockForge instance management

HTTP Crate

The mockforge-http crate provides comprehensive HTTP/REST API mocking capabilities for MockForge, built on top of the Axum web framework. It integrates OpenAPI specification support, AI-powered response generation, comprehensive management APIs, and advanced middleware for observability and traffic control.

Architecture Overview

graph TD
    A[HTTP Server] --> B[Router Builder]
    B --> C{Configuration Type}
    C --> D[OpenAPI Router]
    C --> E[Basic Router]
    C --> F[Auth Router]
    C --> G[Chain Router]

    D --> H[OpenAPI Spec Loader]
    H --> I[Route Registry]
    I --> J[Validation Middleware]

    A --> K[Middleware Stack]
    K --> L[Rate Limiting]
    K --> M[Request Logging]
    K --> N[Metrics Collection]
    K --> O[Tracing]

    A --> P[Management API]
    P --> Q[REST Endpoints]
    P --> R[WebSocket Events]
    P --> S[SSE Streams]

    A --> T[AI Integration]
    T --> U[Intelligent Generation]
    T --> V[Data Drift]

Core Components

Router Building System

The HTTP crate provides multiple router builders for different use cases:

build_router()

Basic router with optional OpenAPI integration:

  • Loads and validates OpenAPI specifications
  • Creates route handlers from spec operations
  • Applies validation middleware
  • Includes health check endpoints

build_router_with_auth()

Router with authentication support:

  • Integrates OAuth2 and JWT authentication
  • Supports custom auth middleware
  • Validates tokens and permissions

build_router_with_chains()

Router with request chaining support:

  • Enables multi-step request workflows
  • Manages chain execution state
  • Provides chain management endpoints

build_router_with_traffic_shaping()

Router with traffic control:

  • Bandwidth limiting and packet loss simulation
  • Network condition emulation
  • Traffic shaping middleware

OpenAPI Integration

Specification Loading

#![allow(unused)]
fn main() {
// Load OpenAPI spec from file
let openapi = OpenApiSpec::from_file("api.yaml").await?;

// Create route registry with validation options
let registry = OpenApiRouteRegistry::new_with_options(
    openapi,
    ValidationOptions::enforce()
);
}

Route Generation

  • Automatic endpoint creation from OpenAPI operations
  • Parameter extraction and validation
  • Response schema validation
  • Error response generation

Validation Modes

  • Strict: Full request/response validation
  • Lenient: Warnings for validation failures
  • Disabled: No validation (performance mode)

Middleware Architecture

Request Processing Pipeline

Request → Rate Limiting → Authentication → Logging → Metrics → Handler → Response

Key Middleware Components

  • Rate Limiting: Uses governor crate for distributed rate limiting
  • Request Logging: Comprehensive HTTP request/response logging
  • Metrics Collection: Prometheus-compatible metrics
  • Tracing: OpenTelemetry integration for distributed tracing
  • Traffic Shaping: Bandwidth and latency control

Management API

REST Endpoints

  • GET /__mockforge/api/health - Health check
  • GET /__mockforge/api/stats - Server statistics
  • GET /__mockforge/routes - Route information
  • GET /__mockforge/coverage - API coverage metrics
  • GET/POST /__mockforge/api/mocks, GET/PUT/DELETE /__mockforge/api/mocks/{id} - Mock management

WebSocket Integration

  • Real-time server events
  • Live request monitoring
  • Interactive mock configuration

Server-Sent Events (SSE)

  • Log streaming to clients
  • Real-time metrics updates
  • Coverage report streaming

AI-Powered Features

Intelligent Mock Generation

#![allow(unused)]
fn main() {
let ai_config = AiResponseConfig {
    enabled: true,
    rag_config: RagConfig {
        provider: "openai".to_string(),
        model: "gpt-4".to_string(),
        api_key: Some(api_key),
    },
    prompt: "Generate realistic user data".to_string(),
};

let response = process_response_with_ai(&ai_config, request_data).await?;
}

Data Drift Simulation

  • Progressive response changes over time
  • Realistic data evolution patterns
  • Configurable drift parameters

Authentication System

Supported Methods

  • OAuth2: Authorization code, client credentials flows
  • JWT: Token validation and claims extraction
  • API Keys: Header and query parameter validation
  • Basic Auth: Username/password authentication

Auth Middleware

#![allow(unused)]
fn main() {
let auth_middleware = auth_middleware(auth_state);
app = app.layer(auth_middleware);
}

Request Chaining

Chain Execution Engine

  • Multi-step request workflows
  • Conditional execution based on responses
  • Chain state management and persistence
  • Execution history and debugging

Chain Management API

  • POST /__mockforge/chains - Create chains
  • GET /__mockforge/chains/{id}/execute - Execute chains
  • GET /__mockforge/chains/{id}/history - View execution history

Multi-Tenant Support

Workspace Isolation

  • Path-based routing (/workspace1/api/*, /workspace2/api/*)
  • Port-based isolation (different ports per tenant)
  • Configuration isolation per workspace

Auto-Discovery

  • Automatic workspace loading from config directories
  • YAML-based workspace definitions
  • Dynamic workspace registration

Observability Integration

Metrics Collection

  • Request/response counts and timings
  • Error rates and status code distribution
  • Route coverage and usage statistics
  • Performance histograms

Tracing Integration

  • Distributed tracing with OpenTelemetry
  • Request correlation IDs
  • Span tagging for operations
  • Jaeger and Zipkin export support

Logging

  • Structured JSON logging
  • Request/response body logging (configurable)
  • Error tracking and correlation
  • Log level configuration

Traffic Shaping and Chaos Engineering

Network Simulation

  • Bandwidth limiting (bytes per second)
  • Packet loss simulation (percentage)
  • Latency injection (fixed or random)
  • Connection failure simulation

Chaos Scenarios

  • Predefined network profiles (3G, 4G, 5G, satellite)
  • Custom traffic shaping rules
  • Circuit breaker patterns
  • Bulkhead isolation

Testing and Validation

Integration Tests

  • End-to-end request/response validation
  • OpenAPI compliance testing
  • Authentication flow testing
  • Performance benchmarking

Coverage Analysis

  • API endpoint coverage tracking
  • Request pattern analysis
  • Missing endpoint detection
  • Coverage reporting and visualization

Key Data Structures

HttpServerState

Shared state for route information and rate limiting:

#![allow(unused)]
fn main() {
pub struct HttpServerState {
    pub routes: Vec<RouteInfo>,
    pub rate_limiter: Option<Arc<GlobalRateLimiter>>,
}
}

ManagementState

Management API state with server statistics:

#![allow(unused)]
fn main() {
pub struct ManagementState {
    pub mocks: Arc<RwLock<Vec<MockConfig>>>,
    pub spec: Option<Arc<OpenApiSpec>>,
    pub request_counter: Arc<RwLock<u64>>,
}
}

AiResponseHandler

AI-powered response generation:

#![allow(unused)]
fn main() {
pub struct AiResponseHandler {
    intelligent_generator: Option<IntelligentMockGenerator>,
    drift_engine: Option<Arc<RwLock<DataDriftEngine>>>,
}
}

Integration Points

Core Dependencies

  • mockforge-core: OpenAPI handling, validation, routing
  • mockforge-data: AI generation, data templating
  • mockforge-observability: Metrics, logging, tracing

External Integrations

  • Axum: Web framework for HTTP handling
  • OpenTelemetry: Distributed tracing
  • Prometheus: Metrics collection
  • OAuth2: Authentication flows
  • Governor: Rate limiting
  • Reqwest: HTTP client for chaining

Performance Considerations

Startup Optimization

  • Lazy OpenAPI spec loading
  • Parallel route registry creation
  • Cached validation schemas
  • Startup time profiling and logging

Runtime Performance

  • Efficient middleware pipeline
  • Minimal allocations in hot paths
  • Async request processing
  • Connection pooling for external calls

Memory Management

  • Shared state with Arc/RwLock
  • Response streaming for large payloads
  • Configurable request body limits
  • Automatic cleanup of expired sessions

Error Handling

Validation Errors

  • Structured error responses
  • OpenAPI-compliant error schemas
  • Configurable error verbosity
  • Error correlation IDs

Recovery Mechanisms

  • Graceful degradation on failures
  • Fallback responses for AI generation
  • Circuit breaker patterns
  • Automatic retry logic

Future Enhancements

  • GraphQL Integration: Schema-based GraphQL mocking
  • WebSocket Mocking: Interactive WebSocket scenarios
  • Advanced Caching: Response caching and invalidation
  • Load Balancing: Multi-instance coordination
  • Plugin Architecture: Extensible middleware system

gRPC Crate

The mockforge-grpc crate provides comprehensive gRPC protocol support for MockForge, featuring dynamic service discovery, runtime protobuf parsing, and HTTP bridge capabilities. It enables automatic mocking of gRPC services without code generation, supporting all streaming patterns and providing rich introspection features.

Architecture Overview

graph TD
    A[gRPC Server] --> B[Dynamic Service Discovery]
    B --> C[Proto Parser]
    C --> D[Service Registry]
    D --> E[Dynamic Service Generator]

    A --> F[gRPC Reflection]
    F --> G[Reflection Proxy]
    G --> H[Descriptor Pool]

    A --> I[HTTP Bridge]
    I --> J[REST API Generator]
    J --> K[OpenAPI Spec]

    A --> L[Streaming Support]
    L --> M[Unary RPC]
    L --> N[Server Streaming]
    L --> O[Client Streaming]
    L --> P[Bidirectional Streaming]

Core Components

Dynamic Service Discovery

The gRPC crate’s core innovation is runtime service discovery and mocking without code generation:

Proto Parser

#![allow(unused)]
fn main() {
// Parse protobuf files at runtime
let mut parser = ProtoParser::new();
parser.parse_directory("./proto").await?;

// Extract services and methods
let services = parser.services();
let descriptor_pool = parser.into_pool();
}

Service Registry

#![allow(unused)]
fn main() {
// Create registry with parsed services
let mut registry = ServiceRegistry::with_descriptor_pool(descriptor_pool);

// Register dynamic service implementations
for (name, proto_service) in services {
    let dynamic_service = DynamicGrpcService::new(proto_service, config);
    registry.register(name, dynamic_service);
}
}

gRPC Reflection

Reflection Proxy

Enables runtime service discovery and method invocation:

#![allow(unused)]
fn main() {
let proxy_config = ProxyConfig::default();
let mock_proxy = MockReflectionProxy::new(proxy_config, registry).await?;

// Server supports reflection queries
// grpcurl -plaintext localhost:50051 list
// grpcurl -plaintext localhost:50051 describe MyService
}

Descriptor Management

  • Descriptor Pool: In-memory protobuf descriptor storage
  • Dynamic Resolution: Runtime method and message resolution
  • Schema Introspection: Full protobuf schema access

HTTP Bridge

REST API Generation

Automatically converts gRPC services to REST endpoints:

#![allow(unused)]
fn main() {
let config = DynamicGrpcConfig {
    enable_http_bridge: true,
    http_bridge_port: 8080,
    generate_openapi: true,
    ..Default::default()
};

// gRPC: MyService/GetUser → HTTP: POST /api/myservice/getuser
}

OpenAPI Generation

  • Automatic OpenAPI 3.0 spec generation from protobuf definitions
  • REST endpoint documentation
  • Request/response schema documentation

Streaming Support

All Streaming Patterns

The crate supports all four gRPC streaming patterns:

  • Unary RPC: Simple request-response
  • Server Streaming: Single request, streaming response
  • Client Streaming: Streaming request, single response
  • Bidirectional Streaming: Streaming in both directions

Streaming Implementation

#![allow(unused)]
fn main() {
// Server streaming
async fn list_users(
    &self,
    request: Request<ListUsersRequest>,
) -> Result<Response<Self::ListUsersStream>, Status> {
    // Return stream of User messages
}

// Bidirectional streaming
async fn chat(
    &self,
    request: Request<Streaming<ChatMessage>>,
) -> Result<Response<Self::ChatStream>, Status> {
    // Handle bidirectional message stream
}
}

Key Modules

dynamic/

Core dynamic service functionality:

proto_parser.rs

  • Runtime protobuf file parsing
  • Service and method extraction
  • Message descriptor generation

service_generator.rs

  • Dynamic service implementation generation
  • Mock response synthesis
  • Streaming method handling

http_bridge/

  • REST API conversion logic
  • OpenAPI specification generation
  • HTTP request/response mapping

reflection/

gRPC reflection protocol implementation:

mock_proxy.rs

  • Reflection service implementation
  • Dynamic method invocation
  • Response generation

client.rs

  • Reflection client for service discovery
  • Dynamic RPC calls
  • Connection pooling

smart_mock_generator.rs

  • AI-powered response generation
  • Schema-aware data synthesis
  • Contextual mock data

registry.rs

Service registration and management:

#![allow(unused)]
fn main() {
pub struct GrpcProtoRegistry {
    services: HashMap<String, ProtoService>,
    descriptor_pool: DescriptorPool,
}
}

Configuration

DynamicGrpcConfig

#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub struct DynamicGrpcConfig {
    pub proto_dir: String,                    // Proto file directory
    pub enable_reflection: bool,              // Enable gRPC reflection
    pub excluded_services: Vec<String>,       // Services to skip
    pub http_bridge: Option<HttpBridgeConfig>, // HTTP bridge settings
    pub max_message_size: usize,              // Max message size
}
}

HTTP Bridge Config

#![allow(unused)]
fn main() {
pub struct HttpBridgeConfig {
    pub enabled: bool,                        // Enable HTTP bridge
    pub port: u16,                           // HTTP server port
    pub generate_openapi: bool,              // Generate OpenAPI specs
    pub cors_enabled: bool,                  // Enable CORS
}
}

Advanced Data Synthesis

Intelligent Field Inference

The crate uses field names and types to generate realistic mock data:

message User {
  string id = 1;           // Generates UUIDs
  string email = 2;        // Generates email addresses
  string phone = 3;        // Generates phone numbers
  repeated string tags = 4; // Generates string arrays
}

Referential Integrity

Maintains relationships between messages:

  • Foreign key relationships
  • Consistent ID generation
  • Cross-message data consistency

Deterministic Seeding

#![allow(unused)]
fn main() {
// Reproducible test data
let config = MockConfig {
    seed: Some(42),
    ..Default::default()
};
}

Performance Features

Connection Pooling

  • Efficient gRPC connection management
  • Connection reuse and lifecycle management
  • Load balancing across connections

Caching

  • Descriptor caching for performance
  • Response caching for repeated requests
  • Schema compilation caching

Async Processing

  • Tokio-based async runtime
  • Streaming data processing
  • Concurrent request handling

Integration Points

Core Dependencies

  • mockforge-core: Base mocking functionality
  • mockforge-data: Advanced data generation
  • mockforge-observability: Metrics and tracing

External Libraries

  • Tonic: gRPC framework for Rust
  • Prost: Protocol buffer implementation
  • Prost-reflect: Runtime protobuf reflection
  • Tokio: Async runtime

Observability

Metrics Collection

  • Request/response counts
  • Method execution times
  • Error rates by service/method
  • Streaming metrics

Tracing Integration

  • OpenTelemetry tracing support
  • Distributed tracing across services
  • Request correlation IDs

Logging

  • Structured logging for all operations
  • Debug logging for request/response payloads
  • Performance logging

Testing Support

Integration Tests

  • End-to-end gRPC testing
  • HTTP bridge validation
  • Reflection service testing
  • Streaming functionality tests

Mock Data Generation

  • Deterministic test data
  • Schema-compliant mock generation
  • Custom data providers

Error Handling

gRPC Status Codes

  • Proper gRPC status code mapping
  • Detailed error messages
  • Error correlation IDs

Recovery Mechanisms

  • Connection retry logic
  • Graceful degradation
  • Fallback responses

Build System

Proto Compilation

The crate uses tonic-prost-build for compile-time proto generation:

// build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::compile_protos("proto/greeter.proto")?;
    Ok(())
}

Feature Flags

  • data-faker: Enable advanced data synthesis
  • Default features include data faker for rich mock data

Usage Examples

Basic gRPC Server

use mockforge_grpc::start;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Auto-discovers services from ./proto directory
    start(50051).await?;
    Ok(())
}

With HTTP Bridge

#![allow(unused)]
fn main() {
use mockforge_grpc::{start_with_config, DynamicGrpcConfig};

let config = DynamicGrpcConfig {
    proto_dir: "./proto".to_string(),
    enable_reflection: true,
    http_bridge: Some(HttpBridgeConfig {
        enabled: true,
        port: 8080,
        generate_openapi: true,
    }),
    ..Default::default()
};

start_with_config(50051, None, config).await?;
}

Client Usage

# List services
grpcurl -plaintext localhost:50051 list

# Describe service
grpcurl -plaintext localhost:50051 describe MyService

# Call method
grpcurl -plaintext -d '{"id": "123"}' localhost:50051 MyService/GetUser

# HTTP bridge
curl -X POST http://localhost:8080/api/myservice/getuser \
  -H "Content-Type: application/json" \
  -d '{"id": "123"}'

Future Enhancements

  • Advanced Streaming: Enhanced bidirectional streaming support
  • Service Mesh Integration: Istio and Linkerd integration
  • Schema Evolution: Automatic handling of protobuf schema changes
  • Load Testing: Built-in gRPC load testing capabilities
  • Code Generation: Optional compile-time service generation

WebSocket Crate

The mockforge-ws crate provides comprehensive WebSocket protocol support for MockForge, featuring replay capabilities, proxy functionality, and AI-powered event generation. It enables realistic WebSocket interaction simulation for testing and development.

Architecture Overview

graph TD
    A[WebSocket Server] --> B[Connection Handler]
    B --> C{Operation Mode}
    C --> D[Replay Mode]
    C --> E[Proxy Mode]
    C --> F[Interactive Mode]
    C --> G[AI Event Mode]

    D --> H[Replay File Parser]
    H --> I[JSONL Processor]
    I --> J[Template Expansion]

    E --> K[Proxy Handler]
    K --> L[Upstream Connection]
    L --> M[Message Forwarding]

    F --> N[Message Router]
    N --> O[Pattern Matching]
    O --> P[Response Generation]

    G --> Q[AI Event Generator]
    Q --> R[LLM Integration]
    R --> S[Event Stream]

Core Components

Connection Management

WebSocket Router

The crate provides multiple router configurations for different use cases:

#![allow(unused)]
fn main() {
// Basic WebSocket router
let app = router();

// With latency simulation
let latency_injector = LatencyInjector::new(profile, Default::default());
let app = router_with_latency(latency_injector);

// With proxy support
let proxy_handler = WsProxyHandler::new(proxy_config);
let app = router_with_proxy(proxy_handler);
}

Connection Lifecycle

  • Establishment: Connection tracking and metrics collection
  • Message Handling: Bidirectional message processing
  • Error Handling: Graceful error recovery and logging
  • Termination: Connection cleanup and statistics recording

Operational Modes

1. Replay Mode

Scripted message playback from JSONL files:

{"ts":0,"dir":"out","text":"HELLO {{uuid}}","waitFor":"^CLIENT_READY$"}
{"ts":10,"dir":"out","text":"{\"type\":\"welcome\",\"sessionId\":\"{{uuid}}\"}"}
{"ts":20,"dir":"out","text":"{\"data\":{{randInt 1 100}}}","waitFor":"^ACK$"}

Features:

  • Timestamp-based message sequencing
  • Template expansion ({{uuid}}, {{now}}, {{randInt min max}})
  • Conditional waiting with regex/JSONPath patterns
  • Deterministic replay for testing

2. Proxy Mode

Forward messages to upstream WebSocket servers:

#![allow(unused)]
fn main() {
let proxy_config = WsProxyConfig {
    upstream_url: "wss://api.example.com/ws".to_string(),
    should_proxy: true,
    message_transform: Some(transform_fn),
};
}

Features:

  • Transparent message forwarding
  • Optional message transformation
  • Connection pooling and reuse
  • Error handling and fallback

3. Interactive Mode

Dynamic responses based on client messages:

#![allow(unused)]
fn main() {
// Echo mode (default)
while let Some(msg) = socket.recv().await {
    if let Ok(Message::Text(text)) = msg {
        let response = format!("echo: {}", text);
        socket.send(Message::Text(response.into())).await?;
    }
}
}

Features:

  • Pattern-based response matching
  • JSONPath query support
  • State-aware conversations
  • Custom response logic

4. AI Event Mode

LLM-powered event stream generation:

#![allow(unused)]
fn main() {
let ai_config = WebSocketAiConfig {
    enabled: true,
    narrative: "Simulate 5 minutes of live stock market trading".to_string(),
    event_count: 20,
    replay: Some(ReplayAugmentationConfig {
        provider: "openai".to_string(),
        model: "gpt-3.5-turbo".to_string(),
        ..Default::default()
    }),
};

let generator = AiEventGenerator::new(ai_config);
generator.stream_events(socket, Some(20)).await;
}

Message Processing

Template Expansion

Rich templating system for dynamic content:

#![allow(unused)]
fn main() {
// UUID generation
"session_{{uuid}}" → "session_550e8400-e29b-41d4-a716-446655440000"

// Timestamp manipulation
"{{now}}" → "2024-01-15T10:30:00Z"
"{{now+1h}}" → "2024-01-15T11:30:00Z"

// Random values
"{{randInt 1 100}}" → "42"
}

JSONPath Matching

Sophisticated message pattern matching:

// Wait for specific message types
{"waitFor": "$.type", "text": "Type received: {{$.type}}"}

// Match nested object properties
{"waitFor": "$.user.id", "text": "User {{$.user.name}} authenticated"}

// Array element matching
{"waitFor": "$.items[0].status", "text": "First item status: {{$.items[0].status}}"}

AI Integration

Event Generation

Narrative-driven event stream creation:

#![allow(unused)]
fn main() {
pub struct AiEventGenerator {
    engine: Arc<RwLock<ReplayAugmentationEngine>>,
}

impl AiEventGenerator {
    pub async fn stream_events(&self, socket: WebSocket, max_events: Option<usize>) {
        // Generate contextual events based on narrative
        let events = self.engine.write().await.generate_stream().await?;
        // Stream events to client with configurable rate
    }
}
}

Replay Augmentation

Enhance existing replay files with AI-generated content:

#![allow(unused)]
fn main() {
let augmentation_config = ReplayAugmentationConfig {
    narrative: "Add realistic user interactions to chat replay".to_string(),
    augmentation_points: vec!["user_message".to_string()],
    provider: "openai".to_string(),
    model: "gpt-4".to_string(),
};
}

Observability

Metrics Collection

Comprehensive WebSocket metrics:

#![allow(unused)]
fn main() {
let registry = get_global_registry();
registry.record_ws_connection_established();
registry.record_ws_message_received();
registry.record_ws_message_sent();
registry.record_ws_connection_closed(duration, status);
}

Tracing Integration

Distributed tracing for WebSocket connections:

#![allow(unused)]
fn main() {
let span = create_ws_connection_span(&request);
let _guard = span.enter();
// Connection handling with tracing context
record_ws_message_success(&span, message_size);
}

Logging

Structured logging for connection lifecycle and message flow:

#![allow(unused)]
fn main() {
info!("WebSocket connection established from {}", peer_addr);
debug!("Received message: {} bytes", message.len());
error!("WebSocket error: {}", error);
}

Performance Features

Connection Pooling

Efficient management of upstream connections in proxy mode:

#![allow(unused)]
fn main() {
// Connection reuse for proxy operations
let connection = pool.get_connection(upstream_url).await?;
connection.forward_message(message).await?;
}

Message Buffering

Optimized message processing with buffering:

#![allow(unused)]
fn main() {
// Stream processing for large message volumes
while let Some(batch) = message_buffer.next_batch().await {
    for message in batch {
        process_message(message).await?;
    }
}
}

Rate Limiting

Configurable message rate limits:

#![allow(unused)]
fn main() {
let rate_limiter = RateLimiter::new(1000, Duration::from_secs(60)); // 1000 msg/min
if rate_limiter.check_limit().await {
    process_message(message).await?;
}
}

Configuration

WebSocket Server Config

#![allow(unused)]
fn main() {
pub struct WsConfig {
    pub port: u16,
    pub max_connections: usize,
    pub max_message_size: usize,
    pub heartbeat_interval: Duration,
    pub replay_file: Option<PathBuf>,
    pub proxy_config: Option<WsProxyConfig>,
    pub ai_config: Option<WebSocketAiConfig>,
}
}

Proxy Configuration

#![allow(unused)]
fn main() {
pub struct WsProxyConfig {
    pub upstream_url: String,
    pub should_proxy: bool,
    pub message_transform: Option<TransformFn>,
    pub connection_pool_size: usize,
    pub retry_attempts: u32,
}
}

AI Configuration

#![allow(unused)]
fn main() {
pub struct WebSocketAiConfig {
    pub enabled: bool,
    pub narrative: String,
    pub event_count: usize,
    pub events_per_second: f64,
    pub replay: Option<ReplayAugmentationConfig>,
}
}

Testing Support

Integration Tests

End-to-end WebSocket testing:

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_websocket_replay() {
    // Start WebSocket server with replay file
    let server = TestServer::new(router()).await;

    // Connect test client
    let (ws_stream, _) = connect_async(server.url()).await?;

    // Verify replay sequence
    let msg = ws_stream.next().await.unwrap()?;
    assert_eq!(msg, Message::Text("HELLO test-session".into()));
}
}

Replay File Validation

Automated validation of replay configurations:

#![allow(unused)]
fn main() {
#[test]
fn test_replay_file_parsing() {
    let replay_data = r#"{"ts":0,"text":"hello","waitFor":"ready"}"#;
    let entry: ReplayEntry = serde_json::from_str(replay_data)?;
    assert_eq!(entry.ts, 0);
    assert_eq!(entry.text, "hello");
}
}

Error Handling

Connection Errors

Graceful handling of connection failures:

#![allow(unused)]
fn main() {
match socket.recv().await {
    Ok(Some(Message::Close(frame))) => {
        info!("Client closed connection: {:?}", frame);
        break;
    }
    Err(e) => {
        error!("WebSocket error: {}", e);
        record_ws_error();
        break;
    }
    _ => continue,
}
}

Message Processing Errors

Robust message parsing and transformation:

#![allow(unused)]
fn main() {
match serde_json::from_str::<Value>(&text) {
    Ok(json) => process_json_message(json).await,
    Err(e) => {
        warn!("Invalid JSON message: {}", e);
        send_error_response("Invalid JSON format").await?;
    }
}
}

Usage Examples

Basic WebSocket Server

use mockforge_ws::start_with_latency;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Start with default latency profile
    start_with_latency(3001, Some(LatencyProfile::normal())).await?;
    Ok(())
}

Replay Mode

# Set environment variable for replay file
export MOCKFORGE_WS_REPLAY_FILE=./replay.jsonl

# Start server
mockforge serve --ws-port 3001

Proxy Mode

#![allow(unused)]
fn main() {
use mockforge_ws::router_with_proxy;
use mockforge_core::{WsProxyConfig, WsProxyHandler};

let proxy_config = WsProxyConfig {
    upstream_url: "wss://api.example.com/ws".to_string(),
    should_proxy: true,
};

let proxy = WsProxyHandler::new(proxy_config);
let app = router_with_proxy(proxy);
}

AI Event Generation

#![allow(unused)]
fn main() {
use mockforge_ws::{AiEventGenerator, WebSocketAiConfig};

let config = WebSocketAiConfig {
    enabled: true,
    narrative: "Simulate real-time chat conversation".to_string(),
    event_count: 50,
    events_per_second: 2.0,
};

let generator = AiEventGenerator::new(config)?;
generator.stream_events_with_rate(socket, None, 2.0).await;
}

Future Enhancements

  • Advanced Pattern Matching: Complex event correlation and state machines
  • Load Testing: Built-in WebSocket load testing capabilities
  • Recording Mode: Capture live WebSocket interactions for replay
  • Clustering: Distributed WebSocket session management
  • Protocol Extensions: Support for custom WebSocket subprotocols

CLI Reference

MockForge provides a comprehensive command-line interface for managing mock servers and generating test data. This reference covers all available commands, options, and usage patterns.

Global Options

All MockForge commands support the following global options:

mockforge-cli [OPTIONS] <COMMAND>

Global Options

  • -h, --help: Display help information

Commands

serve - Start Mock Servers

The primary command for starting MockForge’s mock servers with support for HTTP, WebSocket, and gRPC protocols.

mockforge-cli serve [OPTIONS]

Server Options

Port Configuration:

  • --http-port <PORT>: HTTP server port (default: 3000)
  • --ws-port <PORT>: WebSocket server port (default: 3001)
  • --grpc-port <PORT>: gRPC server port (default: 50051)

API Specification:

  • --spec <PATH>: OpenAPI spec file for HTTP server (JSON or YAML format)

Configuration:

  • -c, --config <PATH>: Path to configuration file

Admin UI Options

Admin UI Control:

  • --admin: Enable admin UI
  • --admin-port <PORT>: Admin UI port (default: 9080)
  • --admin-embed: Force embedding Admin UI under HTTP server
  • --admin-mount-path <PATH>: Explicit mount path for embedded Admin UI (implies --admin-embed)
  • --admin-standalone: Force standalone Admin UI on separate port (overrides embed)
  • --disable-admin-api: Disable Admin API endpoints (UI loads but API routes are absent)

Validation Options

Request Validation:

  • --validation <MODE>: Request validation mode (default: enforce)
    • off: Disable validation
    • warn: Log warnings but allow requests
    • enforce: Reject invalid requests
  • --aggregate-errors: Aggregate request validation errors into JSON array
  • --validate-responses: Validate responses (warn-only)
  • --validation-status <CODE>: Validation error HTTP status code (default: 400)

Response Processing

Template Expansion:

  • --response-template-expand: Expand templating tokens in responses/examples

Chaos Engineering

Latency Simulation:

  • --latency-enabled: Enable latency simulation

Failure Injection:

  • --failures-enabled: Enable failure injection

Examples

Basic HTTP Server:

mockforge-cli serve --spec examples/openapi-demo.json --http-port 3000

Full Multi-Protocol Setup:

mockforge-cli serve \
  --spec examples/openapi-demo.json \
  --http-port 3000 \
  --ws-port 3001 \
  --grpc-port 50051 \
  --admin \
  --admin-port 9080 \
  --response-template-expand

Development Configuration:

mockforge-cli serve \
  --config demo-config.yaml \
  --validation warn \
  --response-template-expand \
  --latency-enabled

Production Configuration:

mockforge-cli serve \
  --config production-config.yaml \
  --validation enforce \
  --admin-standalone

init - Initialize New Project

Create a new MockForge project with a template configuration file.

mockforge-cli init [OPTIONS] <NAME>

Arguments

  • <NAME>: Project name or directory path
    • Use . to initialize in the current directory
    • Use a project name to create a new directory

Options

  • --no-examples: Skip creating example files (only create mockforge.yaml)

Examples

# Create a new project in a new directory
mockforge-cli init my-mock-api

# Initialize in the current directory
mockforge-cli init .

# Initialize without examples
mockforge-cli init my-project --no-examples

What Gets Created

  1. mockforge.yaml: Main configuration file with:

    • HTTP, WebSocket, gRPC server configurations
    • Admin UI settings
    • Core features (latency, failures, overrides)
    • Observability configuration
    • Data generation settings
    • Logging configuration
  2. examples/ directory (unless --no-examples):

    • openapi.json: Sample OpenAPI specification
    • Example data files

See Also


config - Configuration Management

Validate and manage MockForge configuration files.

mockforge-cli config <SUBCOMMAND>

Subcommands

validate - Validate Configuration File

Validate a MockForge configuration file for syntax and structure errors.

mockforge-cli config validate [OPTIONS]

Options:

  • --config <PATH>: Path to config file to validate
    • If omitted, auto-discovers mockforge.yaml or mockforge.yml in current and parent directories

What Gets Validated:

  • YAML syntax and structure
  • File existence
  • HTTP endpoints count
  • Request chains count
  • Missing sections (warnings)

Examples:

# Validate config in current directory
mockforge-cli config validate

# Validate specific config file
mockforge-cli config validate --config my-config.yaml

# Validate before starting server
mockforge-cli config validate && mockforge-cli serve

Output Example:

🔍 Validating MockForge configuration...
📄 Checking configuration file: mockforge.yaml
✅ Configuration is valid

📊 Summary:
   Found 5 HTTP endpoints
   Found 2 chains

⚠️  Warnings:
   - No WebSocket configuration found

Common Issues:

  • Invalid YAML syntax: Fix indentation, quotes, or structure
  • File not found: Check path or run mockforge init
  • Missing sections: Add HTTP, admin, or other required sections

Note: Current validation is basic (syntax, structure, counts). For comprehensive field validation, see the Configuration Validation Guide.

See Also


data - Generate Synthetic Data

Generate synthetic test data using various templates and schemas.

mockforge-cli data <SUBCOMMAND>

Subcommands

template - Generate from Built-in Templates

Generate data using MockForge’s built-in data generation templates.

mockforge-cli data template [OPTIONS]

Options:

  • --count <N>: Number of items to generate (default: 1)
  • --format <FORMAT>: Output format (json, yaml, csv)
  • --template <NAME>: Template name (user, product, order, etc.)
  • --output <PATH>: Output file path

Examples:

# Generate 10 user records as JSON
mockforge-cli data template --template user --count 10 --format json

# Generate product data to file
mockforge-cli data template --template product --count 50 --output products.json
schema - Generate from JSON Schema

Generate data conforming to a JSON Schema specification.

mockforge-cli data schema [OPTIONS] <SCHEMA>

Parameters:

  • <SCHEMA>: Path to JSON Schema file

Options:

  • --count <N>: Number of items to generate (default: 1)
  • --format <FORMAT>: Output format (json, yaml)
  • --output <PATH>: Output file path

Examples:

# Generate data from user schema
mockforge-cli data schema --count 5 user-schema.json

# Generate and save to file
mockforge-cli data schema --count 100 --output generated-data.json api-schema.json
open-api - Generate from OpenAPI Spec

Generate mock data based on OpenAPI specification schemas.

mockforge-cli data open-api [OPTIONS] <SPEC>

Parameters:

  • <SPEC>: Path to OpenAPI specification file

Options:

  • --endpoint <PATH>: Specific endpoint to generate data for
  • --method <METHOD>: HTTP method (get, post, put, delete)
  • --count <N>: Number of items to generate (default: 1)
  • --format <FORMAT>: Output format (json, yaml)
  • --output <PATH>: Output file path

Examples:

# Generate data for all endpoints in OpenAPI spec
mockforge-cli data open-api api-spec.yaml

# Generate data for specific endpoint
mockforge-cli data open-api --endpoint /users --method get --count 20 api-spec.yaml

# Generate POST request body data
mockforge-cli data open-api --endpoint /users --method post api-spec.yaml

admin - Admin UI Server

Start the Admin UI as a standalone server without the main mock servers.

mockforge-cli admin [OPTIONS]

Options

  • --port <PORT>: Server port (default: 9080)

Examples

# Start admin UI on default port
mockforge-cli admin

# Start admin UI on custom port
mockforge-cli admin --port 9090

bench - OpenAPI-driven Load Testing

Generate and run a k6 load test from an OpenAPI spec.

mockforge bench --spec api.yaml --target http://localhost:3000 [OPTIONS]

Common Options

  • -s, --spec <PATH> — OpenAPI spec file (repeatable for multi-spec mode).
  • --spec-dir <DIR> — Directory of specs (auto-discovered).
  • -t, --target <URL> — Target server URL.
  • -d, --duration <SECS> — Run length (default: 60).
  • --vus <N> — Virtual users (default: 10).
  • --scenario <NAME> — constant | ramp-up | spike | stress | soak.
  • --operations <FILTER> — Comma-separated operation filter (e.g. "GET /users,POST /orders").
  • --auth <HEADER> — Authorization header value (e.g. "Bearer $TOKEN").
  • --headers <KV> — Comma-separated extra headers (e.g. "X-Tenant: a,X-Region: b").
  • --threshold-percentile <P> / --threshold-ms <N> — Latency SLO.
  • --max-error-rate <RATE> — Error-rate SLO (0.01 = 1%).
  • --generate-only — Write the k6 script without running it.
  • --script-output <PATH> — Where to write the generated script.
  • --targets-file <PATH> — Multi-target mode (one URL per line).
  • --max-concurrency <N> — Parallel target limit (default: 10).
  • --insecure — Skip TLS verification (test self-signed certs).
  • --chunked-request-bodies — Add Transfer-Encoding: chunked to every k6 request body. NOTE: k6 runs on Go’s net/http, which may still send Content-Length based on body type. For guaranteed wire chunking use bench-chunked instead.

See the Load Testing chapter for the full options surface (security testing, OWASP API top 10, conformance mode, data-driven testing) and end-to-end examples.

bench-chunked - Native Chunked Traffic Generator

Send guaranteed Transfer-Encoding: chunked request bodies via hyper. Useful when bench --chunked-request-bodies falls back to Content-Length (Go’s transport heuristics) and you need real chunked traffic on the wire.

mockforge bench-chunked --target http://localhost:3000/upload [OPTIONS]

Options

  • --target <URL> — Target URL. Required unless --targets-file is given.
  • --targets-file <FILE> — Bench every target in the file in parallel (same text/JSON format as bench --targets-file, including per-target auth, headers, spec). Mutually exclusive with --target.
  • --max-concurrency <N> — Max targets benched at once with --targets-file (default: 10).
  • --method <METHOD> — POST (default), PUT, or PATCH.
  • -c, --concurrency <N> — Concurrent workers per target (default: 10).
  • -d, --duration <DURATION> — Run length, per operation with --spec (default: 30s).
  • --chunk-size-bytes <N> — Bytes per chunk (default: 1024).
  • --total-size-bytes <N> — Total body size per request (default: 1048576 = 1 MiB).
  • --chunk-interval-ms <MS> — Sleep between chunks (default: 0 = back-to-back).
  • --header <NAME: VALUE> — Extra header (repeatable).
  • --insecure — Skip TLS verification.
  • --rps <N> — Cap on request starts per second, per target.
  • --cps — Open a new connection for every request (connections/s = requests/s).
  • --rounds <N> / --repeat-until <DURATION> — Campaign: re-run the whole pass; rounds go to <output>/round_N/, stats to campaign.jsonl and round-summaries/.
  • --keep-rounds <N> — Campaign only: keep the newest N round_* dirs.

Reports req/s, p50/p95/p99 latency, and a status-code distribution at the end.

git-watch - Watch a Git Repo for Spec Changes

Monitor a Git repository for changes to OpenAPI / spec files and automatically reload the local mock server when they change. Useful for teams that store specs in a separate repo from their mock config.

mockforge git-watch https://github.com/user/api-specs \
  --reload-command "mockforge serve --spec"

Common options: --branch, --poll-interval, --auth-token (for private repos), --cache-dir, --spec-paths (comma-separated globs to watch).

contract-sync - Sync Contracts from a Git Repo

One-shot pull of OpenAPI / contract specs from a Git repository, with an optional report comparing the new spec against the current mock config.

mockforge contract-sync https://github.com/user/api-specs \
  --update --output report.md

Use --update to overwrite local copies; omit it for a dry-run report. Pairs well with CI — fail the build if the upstream contract drifted from what the mock returns.

validate-fixtures - Validate Fixture Files

Lint a directory or single file of fixture data against MockForge’s schema. Useful pre-commit guard for repos that check fixtures into source control.

# Validate every fixture in a directory
mockforge validate-fixtures --dir ./fixtures

# Validate one file
mockforge validate-fixtures --file ./fixtures/users.json

# Verbose mode — show per-fixture details, not just failures
mockforge validate-fixtures --dir ./fixtures --verbose

Exit code 0 on clean, non-zero on any validation failure.

mockforge-tui - Terminal Dashboard (separate binary)

Live dashboard in the terminal showing server status, system metrics (current and lifetime peak CPU / memory / error rate), request stats, and recent logs. Auto-refreshes every 2 s.

mockforge-tui

Optionally pair with MOCKFORGE_METRICS_LOG_FILE=path.csv to also append a persistent CSV record while the server runs.

bench-pipeline - HTTP Pipelining Load Test

Load-test a target with HTTP pipelining: synthetic request bodies (json / xml / urlencoded / multipart) are written back-to-back per connection before any response is read.

mockforge bench-pipeline --target http://localhost:3000/api \
  --content-type json --body-size 500KB --pipeline-depth 16 \
  --connections 8 --duration 30s

Options

  • --target <url> (required): plain-http:// target URL.
  • --method <method>: HTTP method; pipelining is only meaningful with bodies, so the default is POST.
  • --content-type <flavour>: json | xml | urlencoded | multipart (default json).
  • --body-size <size>: exact body size per request — bare bytes or KB/MB/GB / KiB/MiB/GiB (default 1KB).
  • --pipeline-depth <n>: requests in flight per connection before reading responses (default 16).
  • --connections <n>: concurrent connections (default 8).

verify-mocks - Mock Fidelity / Drift Detection

Compare the mocks generated from an OpenAPI spec against real captured traffic in a recorder database, and report drift: endpoints whose mocks no longer match how clients actually call them.

mockforge verify-mocks --spec openapi.json --capture-db recorder.sqlite

Options

  • --spec <path> (required): OpenAPI spec the mocks were generated from (3.x natively; Swagger 2.0 is up-converted automatically).
  • --capture-db <path> (required): recorder SQLite database holding captured traffic (what mockforge serve --recorder writes; the default path is ./mockforge-recordings.db).
  • --limit <n>: maximum exchanges to evaluate, oldest first (default 500).
  • --fail-on-drift: exit with code 1 when any drift is found — use as a CI gate.
  • --output <path>: write the structured drift report as JSON.

sync - Workspace Synchronization Daemon

Start a background daemon that monitors a workspace directory for file changes and automatically syncs them to MockForge workspaces.

mockforge-cli sync [OPTIONS]

Options

Required:

  • --workspace-dir <PATH> or -w <PATH>: Workspace directory to monitor for changes

Optional:

  • --config <PATH> or -c <PATH>: Configuration file path for sync settings

How It Works

The sync daemon provides bidirectional synchronization between workspace files and MockForge’s internal workspace storage:

  1. File Monitoring: Watches for .yaml and .yml files in the workspace directory
  2. Automatic Import: When files are created or modified, they’re automatically imported into the workspace
  3. Real-time Updates: Changes are detected and processed immediately
  4. Visual Feedback: Clear console output shows what’s happening in real-time

File Requirements:

  • Only .yaml and .yml files are monitored
  • Hidden files (starting with .) are ignored
  • Files must be valid MockRequest YAML format

What You’ll See:

  • File creation notifications with import status
  • File modification notifications with update status
  • File deletion notifications (files are not auto-deleted from workspace)
  • Error messages if imports fail
  • Real-time feedback for all sync operations

Examples

Basic Usage:

# Start sync daemon for a workspace directory
mockforge-cli sync --workspace-dir ./my-workspace

# Use short form
mockforge-cli sync -w ./my-workspace

# With custom config
mockforge-cli sync --workspace-dir /path/to/workspace --config sync-config.yaml

Git Integration:

# Monitor a Git repository directory
mockforge-cli sync --workspace-dir /path/to/git/repo/workspaces

# Changes you make in Git will automatically sync to MockForge
# Perfect for team collaboration via Git

Development Workflow:

# 1. Start the sync daemon in one terminal
mockforge-cli sync --workspace-dir ./workspaces

# 2. In another terminal, edit workspace files
vim ./workspaces/my-request.yaml

# 3. Save the file - it will automatically import to MockForge
# You'll see output like:
#   🔄 Detected 1 file change in workspace 'default'
#     📝 Modified: my-request.yaml
#        ✅ Successfully updated

Example Output

When you start the sync daemon, you’ll see:

🔄 Starting MockForge Sync Daemon...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 Workspace directory: ./my-workspace

ℹ️  What the sync daemon does:
   • Monitors the workspace directory for .yaml/.yml file changes
   • Automatically imports new or modified request files
   • Syncs changes bidirectionally between files and workspace
   • Skips hidden files (starting with .)

🔍 Monitoring for file changes...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✅ Sync daemon started successfully!
💡 Press Ctrl+C to stop

📂 Monitoring workspace 'default' in directory: ./my-workspace

When files change, you’ll see:

🔄 Detected 1 file change in workspace 'default'
  ➕ Created: new-endpoint.yaml
     ✅ Successfully imported

🔄 Detected 2 file changes in workspace 'default'
  📝 Modified: user-api.yaml
     ✅ Successfully updated
  🗑️  Deleted: old-endpoint.yaml
     ℹ️  Auto-deletion from workspace is disabled

If errors occur:

🔄 Detected 1 file change in workspace 'default'
  📝 Modified: invalid-file.yaml
     ⚠️  Failed to import: File is not a recognized format (expected MockRequest YAML)

Stopping the Daemon

Press Ctrl+C to gracefully stop the sync daemon:

^C
🛑 Received shutdown signal
⏹️  Stopped monitoring workspace 'default' in directory: ./my-workspace
👋 Sync daemon stopped

Best Practices

Version Control:

# Use sync with Git for team collaboration
cd /path/to/git/repo
mockforge-cli sync --workspace-dir ./workspaces

# Team members can push/pull changes
# The sync daemon will automatically import updates

Development Workflow:

# Keep sync daemon running during development
# Edit files in your favorite editor
# Changes automatically sync to MockForge
# Perfect for file-based workflows

Directory Organization:

# Organize workspace files in subdirectories
workspaces/
├── api-v1/
│   ├── users.yaml
│   └── products.yaml
├── api-v2/
│   └── users.yaml
└── internal/
    └── admin.yaml

# All .yaml files will be monitored
mockforge-cli sync --workspace-dir ./workspaces

Troubleshooting

Files not importing:

  • Ensure files have .yaml or .yml extension
  • Check that files are valid MockRequest YAML format
  • Look for error messages in the console output
  • Verify files are not hidden (don’t start with .)

Permission errors:

  • Ensure MockForge has read access to the workspace directory
  • Check file permissions: ls -la workspace-dir/

Changes not detected:

  • The sync daemon uses filesystem notifications
  • Some network filesystems may not support change notifications
  • Try editing the file locally rather than over a network mount

Enable debug logging:

RUST_LOG=mockforge_core::sync_watcher=debug mockforge-cli sync --workspace-dir ./workspace

Configuration File Format

MockForge supports YAML configuration files that can be used instead of command-line options.

Basic Configuration Structure

# Server configuration
server:
  http_port: 3000
  ws_port: 3001
  grpc_port: 50051

# API specification
spec: examples/openapi-demo.json

# Admin UI configuration
admin:
  enabled: true
  port: 9080
  embedded: false
  mount_path: "/admin"
  standalone: true
  disable_api: false

# Validation settings
validation:
  mode: enforce
  aggregate_errors: false
  validate_responses: false
  status_code: 400

# Response processing
response:
  template_expand: true

# Chaos engineering
chaos:
  latency_enabled: false
  failures_enabled: false

# Protocol-specific settings
grpc:
  proto_dir: "proto/"
  enable_reflection: true

websocket:
  replay_file: "examples/ws-demo.jsonl"

Configuration Precedence

Configuration values are applied in the following order (later sources override earlier ones):

  1. Default values (compiled into the binary)
  2. Configuration file (-c/--config option)
  3. Environment variables
  4. Command-line arguments (highest priority)

Environment Variables

All configuration options can be set via environment variables using the MOCKFORGE_ prefix:

# Server ports
export MOCKFORGE_HTTP_PORT=3000
export MOCKFORGE_WS_PORT=3001
export MOCKFORGE_GRPC_PORT=50051

# Admin UI
export MOCKFORGE_ADMIN_ENABLED=true
export MOCKFORGE_ADMIN_PORT=9080

# WebSocket settings
export MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl

# gRPC settings
export MOCKFORGE_PROTO_DIR=proto/

# Data generation (RAG)
export MOCKFORGE_RAG_ENABLED=true
export MOCKFORGE_RAG_PROVIDER=openai
export MOCKFORGE_RAG_API_KEY=your-api-key

For the full env-var surface, see Environment Variables. Plugin system, admin auth, encryption, sync daemon, and validation toggles are configured via YAML rather than env vars; see the relevant chapter for each.

Exit Codes

MockForge uses standard exit codes:

  • 0: Success
  • 1: General error
  • 2: Configuration error
  • 3: Validation error
  • 4: File I/O error
  • 5: Network error

Logging

MockForge provides configurable logging output to help with debugging and monitoring.

Log Levels

  • error: Only error messages
  • warn: Warnings and errors
  • info: General information (default)
  • debug: Detailed debugging information
  • trace: Very verbose tracing information

Log Configuration

# Set log level via environment variable
export RUST_LOG=mockforge=debug

# Or via configuration file
logging:
  level: debug
  format: json

Log Output

Logs include structured information about:

  • HTTP requests/responses
  • WebSocket connections and messages
  • gRPC calls and streaming
  • Configuration loading
  • Template expansion
  • Validation errors

Examples

Complete Development Setup

# Start all servers with admin UI
mockforge-cli serve \
  --spec examples/openapi-demo.json \
  --http-port 3000 \
  --ws-port 3001 \
  --grpc-port 50051 \
  --admin \
  --admin-port 9080 \
  --response-template-expand \
  --validation warn

CI/CD Testing Pipeline

#!/bin/bash
# test-mockforge.sh

# Start MockForge in background
mockforge-cli serve --spec api-spec.yaml --http-port 3000 &
SERVER_PID=$!

# Wait for server to start
sleep 5

# Run API tests
npm test

# Generate test data
mockforge-cli data open-api --endpoint /users --count 100 api-spec.yaml > test-users.json

# Stop MockForge
kill $SERVER_PID

Load Testing Setup

#!/bin/bash
# load-test-setup.sh

# Start MockForge with minimal validation for performance
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=false \
mockforge-cli serve \
  --spec load-test-spec.yaml \
  --http-port 3000 \
  --validation off

# Now run your load testing tool against localhost:3000
# Example: hey -n 10000 -c 100 http://localhost:3000/api/test

Docker Integration

# Run MockForge in Docker with CLI commands
docker run --rm -v $(pwd)/examples:/examples \
  mockforge \
  serve --spec /examples/openapi-demo.json --http-port 3000

Troubleshooting

Common Issues

Server won’t start:

# Check if ports are available
lsof -i :3000
lsof -i :3001

# Try different ports
mockforge-cli serve --http-port 3001 --ws-port 3002

Configuration not loading:

# Validate YAML syntax
yamllint config.yaml

# Check file permissions
ls -la config.yaml

OpenAPI spec not found:

# Verify file exists and path is correct
ls -la examples/openapi-demo.json

# Use absolute path
mockforge-cli serve --spec /full/path/to/examples/openapi-demo.json

Template expansion not working:

# Ensure template expansion is enabled
mockforge-cli serve --response-template-expand --spec api-spec.yaml

Debug Mode

Run with debug logging for detailed information:

RUST_LOG=mockforge=debug mockforge-cli serve --spec api-spec.yaml

Health Checks

Test basic functionality:

# HTTP health check
curl http://localhost:3000/health

# WebSocket connection test
websocat ws://localhost:3001/ws

# gRPC service discovery
grpcurl -plaintext localhost:50051 list

This CLI reference provides comprehensive coverage of MockForge’s command-line interface. For programmatic usage, see the Rust API Reference.

Admin UI REST API

This document provides comprehensive documentation for the MockForge Admin UI REST API endpoints.

Overview

The MockForge Admin UI provides a web-based interface for managing and monitoring MockForge servers. The API is organized around the following main areas:

  • Dashboard: System overview and real-time metrics
  • Server Management: Control and monitor server instances
  • Configuration: Update latency, faults, proxy, and validation settings
  • Logging: View and filter request logs
  • Metrics: Performance monitoring and analytics
  • Fixtures: Manage mock data and fixtures
  • Environment: Environment variable management

Base URL

All admin endpoints live under the /__mockforge prefix to avoid conflicts with user-defined routes. Two routers use it:

  • The admin server (--admin, default port 9080) serves the endpoints on this page, such as /__mockforge/dashboard, /__mockforge/logs and /__mockforge/config.
  • The HTTP mock server (default port 3000) serves the management API under /__mockforge/api/*, for example /__mockforge/api/mocks.

Ports

  • Admin UI and admin endpoints run on a separate port (default: 9080): http://localhost:9080/__mockforge/*, for example curl http://localhost:9080/__mockforge/dashboard
  • The management API runs on the HTTP server (default: 3000): http://localhost:3000/__mockforge/api/*, for example curl http://localhost:3000/__mockforge/api/mocks

The Admin UI always runs on its own port; it cannot be mounted under a path of the HTTP server.

Configuration via REST API (JSON over HTTP):

The REST API supports full configuration management via JSON over HTTP, making it suitable for:

  • CI/CD pipelines
  • Automated testing
  • Remote configuration
  • Integration with external tools

All endpoints accept and return JSON, following standard REST conventions.

Standalone Mode Examples

Starting MockForge in Standalone Mode:

# Start MockForge with the admin UI
mockforge serve --admin --admin-port 9080

# Or via config file
# admin:
#   enabled: true
#   port: 9080
#   api_enabled: true

Creating a Mock via REST API (Standalone Mode):

# Create a mock using JSON over HTTP
curl -X POST http://localhost:9080/__mockforge/api/mocks \
  -H "Content-Type: application/json" \
  -d '{
    "id": "user-get",
    "name": "Get User",
    "method": "GET",
    "path": "/api/users/{id}",
    "response": {
      "body": {
        "id": "{{request.path.id}}",
        "name": "Alice",
        "email": "[email protected]"
      },
      "headers": {
        "Content-Type": "application/json"
      }
    },
    "enabled": true,
    "status_code": 200
  }'

Updating Configuration via REST API:

# Update latency configuration
curl -X POST http://localhost:9080/__mockforge/api/config/latency \
  -H "Content-Type: application/json" \
  -d '{
    "base_ms": 100,
    "jitter_ms": 50
  }'

Listing All Mocks:

# Get all configured mocks
curl http://localhost:9080/__mockforge/api/mocks

Using the SDK with Standalone Mode:

use mockforge_sdk::AdminClient;
use mockforge_sdk::MockConfigBuilder;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to standalone admin API
    let client = AdminClient::new("http://localhost:9080");
    
    // Create a mock using the fluent builder API
    let mock = MockConfigBuilder::new("POST", "/api/users")
        .name("Create User")
        .with_header("Authorization", "Bearer.*")
        .with_query_param("role", "admin")
        .status(201)
        .body(json!({
            "id": "{{uuid}}",
            "name": "{{faker.name}}",
            "created": true
        }))
        .priority(10)
        .build();
    
    // Create the mock via REST API
    client.create_mock(mock).await?;
    
    Ok(())
}

Authentication

Currently, the API does not implement authentication. In production deployments, consider adding authentication middleware.

Response Format

All API responses follow a consistent format:

{
  "success": boolean,
  "data": object | array | null,
  "error": string | null,
  "timestamp": string
}

Success Response

{
  "success": true,
  "data": { ... },
  "error": null,
  "timestamp": "2025-09-17T10:30:00Z"
}

Error Response

{
  "success": false,
  "data": null,
  "error": "Error message",
  "timestamp": "2025-09-17T10:30:00Z"
}

API Endpoints

Dashboard

GET /__mockforge/dashboard

Get comprehensive dashboard data including system information, server status, routes, and recent logs.

Response:

{
  "success": true,
  "data": {
    "system": {
      "version": "0.1.0",
      "uptime_seconds": 3600,
      "memory_usage_mb": 128,
      "cpu_usage_percent": 15.5,
      "active_threads": 8,
      "total_routes": 25,
      "total_fixtures": 150
    },
    "servers": [
      {
        "server_type": "HTTP",
        "address": "127.0.0.1:3000",
        "running": true,
        "start_time": "2025-09-17T09:30:00Z",
        "uptime_seconds": 3600,
        "active_connections": 5,
        "total_requests": 1250
      }
    ],
    "routes": [
      {
        "method": "GET",
        "path": "/api/users",
        "priority": 0,
        "has_fixtures": true,
        "latency_ms": 45,
        "request_count": 125,
        "last_request": "2025-09-17T10:25:00Z",
        "error_count": 2
      }
    ],
    "recent_logs": [
      {
        "id": "log_1",
        "timestamp": "2025-09-17T10:29:00Z",
        "method": "GET",
        "path": "/api/users",
        "status_code": 200,
        "response_time_ms": 45,
        "client_ip": "127.0.0.1",
        "user_agent": "test-agent",
        "headers": {},
        "response_size_bytes": 1024,
        "error_message": null
      }
    ],
    "latency_profile": {
      "name": "default",
      "base_ms": 50,
      "jitter_ms": 20,
      "tag_overrides": {}
    },
    "fault_config": {
      "enabled": false,
      "failure_rate": 0.0,
      "status_codes": [500],
      "active_failures": 0
    },
    "proxy_config": {
      "enabled": false,
      "upstream_url": null,
      "timeout_seconds": 30,
      "requests_proxied": 0
    }
  }
}

Health Check

GET /__mockforge/health

Get system health status.

Response:

{
  "status": "healthy",
  "services": {
    "http": "healthy",
    "websocket": "healthy",
    "grpc": "healthy"
  },
  "last_check": "2025-09-17T10:30:00Z",
  "issues": []
}

Server Management

GET /__mockforge/server-info

Get information about server addresses and configuration.

Response:

{
  "success": true,
  "data": {
    "http_server": "127.0.0.1:3000",
    "ws_server": "127.0.0.1:3001",
    "grpc_server": "127.0.0.1:50051"
  }
}

POST /__mockforge/restart

Initiate server restart. No request body is required.

Response:

{
  "success": true,
  "data": {
    "message": "Server restart initiated. Please wait for completion."
  }
}

GET /__mockforge/restart/status

Get restart status.

Response:

{
  "success": true,
  "data": {
    "in_progress": false,
    "initiated_at": null,
    "reason": null,
    "success": null
  }
}

Routes

GET /__mockforge/routes

Get information about configured routes (proxied to HTTP server).

Logs

GET /__mockforge/logs

Get request logs with optional filtering.

Query Parameters:

  • method (string): Filter by HTTP method
  • path (string): Filter by path pattern
  • status (number): Filter by status code
  • limit (number): Maximum number of results

Examples:

GET /__mockforge/logs?method=GET&limit=50
GET /__mockforge/logs?path=/api/users&status=200

Response:

{
  "success": true,
  "data": [
    {
      "id": "log_1",
      "timestamp": "2025-09-17T10:29:00Z",
      "method": "GET",
      "path": "/api/users",
      "status_code": 200,
      "response_time_ms": 45,
      "client_ip": "127.0.0.1",
      "user_agent": "test-agent",
      "headers": {},
      "response_size_bytes": 1024,
      "error_message": null
    }
  ]
}

DELETE /__mockforge/logs

Clear all request logs.

Response:

{
  "success": true,
  "data": {
    "message": "Logs cleared"
  }
}

Metrics

GET /__mockforge/metrics

Get performance metrics and analytics.

Response:

{
  "success": true,
  "data": {
    "requests_by_endpoint": {
      "GET /api/users": 125,
      "POST /api/users": 45
    },
    "response_time_percentiles": {
      "p50": 45,
      "p95": 120,
      "p99": 250
    },
    "error_rate_by_endpoint": {
      "GET /api/users": 0.02,
      "POST /api/users": 0.0
    },
    "memory_usage_over_time": [
      ["2025-09-17T10:25:00Z", 120],
      ["2025-09-17T10:26:00Z", 125]
    ],
    "cpu_usage_over_time": [
      ["2025-09-17T10:25:00Z", 12.5],
      ["2025-09-17T10:26:00Z", 15.2]
    ]
  }
}

Configuration

GET /__mockforge/config

Get current configuration settings.

Response:

{
  "success": true,
  "data": {
    "latency": {
      "enabled": true,
      "base_ms": 50,
      "jitter_ms": 20,
      "tag_overrides": {}
    },
    "faults": {
      "enabled": false,
      "failure_rate": 0.0,
      "status_codes": [500, 502, 503]
    },
    "proxy": {
      "enabled": false,
      "upstream_url": null,
      "timeout_seconds": 30
    },
    "validation": {
      "mode": "enforce",
      "aggregate_errors": true,
      "validate_responses": false,
      "overrides": {}
    }
  }
}

POST /__mockforge/config/latency

Update latency configuration.

Request Body:

{
  "config_type": "latency",
  "data": {
    "base_ms": 100,
    "jitter_ms": 50,
    "tag_overrides": {
      "auth": 200
    }
  }
}

POST /__mockforge/config/faults

Update fault injection configuration.

Request Body:

{
  "config_type": "faults",
  "data": {
    "enabled": true,
    "failure_rate": 0.1,
    "status_codes": [500, 502, 503]
  }
}

POST /__mockforge/config/proxy

Update proxy configuration.

Request Body:

{
  "config_type": "proxy",
  "data": {
    "enabled": true,
    "upstream_url": "http://api.example.com",
    "timeout_seconds": 60
  }
}

POST /__mockforge/validation

Update validation settings.

Request Body:

{
  "mode": "warn",
  "aggregate_errors": false,
  "validate_responses": true,
  "overrides": {
    "GET /health": "off"
  }
}

Environment Variables

GET /__mockforge/env

Get relevant environment variables.

Response:

{
  "success": true,
  "data": {
    "MOCKFORGE_LATENCY_ENABLED": "true",
    "MOCKFORGE_HTTP_PORT": "3000",
    "RUST_LOG": "info"
  }
}

POST /__mockforge/env

Update an environment variable (runtime only).

Request Body:

{
  "key": "MOCKFORGE_LOG_LEVEL",
  "value": "debug"
}

Response:

{
  "success": true,
  "data": {
    "message": "Environment variable MOCKFORGE_LOG_LEVEL updated to 'debug'. Note: This change is not persisted and will be lost on restart."
  }
}

Files

POST /__mockforge/files/content

Get file content.

Request Body:

{
  "file_path": "config.yaml",
  "file_type": "yaml"
}

Response:

{
  "success": true,
  "data": "http:\n  request_validation: \"enforce\"\n  aggregate_validation_errors: true\n"
}

POST /__mockforge/files/save

Save file content.

Request Body:

{
  "file_path": "config.yaml",
  "content": "http:\n  port: 9080\n"
}

Response:

{
  "success": true,
  "data": {
    "message": "File saved successfully"
  }
}

Fixtures

GET /__mockforge/fixtures

Get all fixtures with metadata.

Response:

{
  "success": true,
  "data": [
    {
      "id": "fixture_123",
      "protocol": "http",
      "method": "GET",
      "path": "/api/users",
      "saved_at": "2025-09-17T09:00:00Z",
      "file_size": 2048,
      "file_path": "http/get/api_users_123.json",
      "fingerprint": "abc123",
      "metadata": { ... }
    }
  ]
}

POST /__mockforge/fixtures/delete

Delete a fixture.

Request Body:

{
  "fixture_id": "fixture_123"
}

POST /__mockforge/fixtures/delete-bulk

Delete multiple fixtures.

Request Body:

{
  "fixture_ids": ["fixture_123", "fixture_456"]
}

Response:

{
  "success": true,
  "data": {
    "deleted_count": 2,
    "total_requested": 2,
    "errors": []
  }
}

GET /__mockforge/fixtures/download?id=fixture_123

Download a fixture file.

Response: Binary file download

Smoke Tests

GET /__mockforge/smoke

Get smoke test results.

GET /__mockforge/smoke/run

Run smoke tests against fixtures.

Response:

{
  "success": true,
  "data": {
    "message": "Smoke tests started. Check results in the smoke tests section."
  }
}

Error Codes

HTTP Status Codes

  • 200 OK: Success
  • 400 Bad Request: Invalid request parameters
  • 404 Not Found: Endpoint or resource not found
  • 500 Internal Server Error: Server error

Common Error Messages

  • "Invalid config type": Configuration update with invalid type
  • "Failed to load fixtures": Error reading fixture files
  • "Path traversal detected": Security violation in file paths
  • "Server restart already in progress": Attempted restart while one is running

Rate Limiting

Currently, no rate limiting is implemented. Consider adding rate limiting for production deployments.

CORS

The API includes CORS middleware allowing cross-origin requests from web applications.

WebSocket Support

The admin UI supports real-time updates through WebSocket connections for live monitoring of metrics and logs.

Examples

Complete Dashboard Fetch

const response = await fetch('/__mockforge/dashboard');
const data = await response.json();

if (data.success) {
  console.log('System uptime:', data.data.system.uptime_seconds);
  console.log('Active servers:', data.data.servers.length);
}

Update Latency Configuration

const response = await fetch('/__mockforge/config/latency', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    config_type: 'latency',
    data: {
      base_ms: 100,
      jitter_ms: 25
    }
  })
});

const result = await response.json();
console.log(result.data.message);

Filter Logs

const response = await fetch('/__mockforge/logs?method=GET&status=200&limit=100');
const data = await response.json();

data.data.forEach(log => {
  console.log(`${log.method} ${log.path} - ${log.status_code} (${log.response_time_ms}ms)`);
});

Development

Running Tests

# Run all tests
cargo test --package mockforge-ui

# Run integration tests
cargo test --package mockforge-ui --test integration

# Run smoke tests
cargo test --package mockforge-ui --test smoke

Building Documentation

# Generate API documentation
cargo doc --package mockforge-ui --open

Security Considerations

  1. Input Validation: All inputs should be validated
  2. Path Traversal: File operations prevent directory traversal
  3. Rate Limiting: Consider implementing rate limiting
  4. Authentication: Add authentication for production use
  5. HTTPS: Use HTTPS in production
  6. CORS: Properly configure CORS policies

Contributing

When adding new API endpoints:

  1. Follow the established response format
  2. Add comprehensive error handling
  3. Include integration tests
  4. Update this documentation
  5. Ensure proper CORS and security measures

Rust API Reference

MockForge provides comprehensive Rust libraries for programmatic usage and extension. This reference covers the main crates and their APIs.

Crate Overview

MockForge consists of several interconnected crates:

  • mockforge-cli: Command-line interface and main executable
  • mockforge-core: Core functionality shared across protocols
  • mockforge-http: HTTP REST API mocking
  • mockforge-grpc: gRPC service mocking
  • mockforge-ui: Web-based admin interface

Getting Started

Add MockForge to your Cargo.toml:

[dependencies]
mockforge-core = "0.1"
mockforge-http = "0.1"
mockforge-grpc = "0.1"

For development or testing, you might want to use path dependencies:

[dependencies]
mockforge-core = { path = "../mockforge/crates/mockforge-core" }
mockforge-http = { path = "../mockforge/crates/mockforge-http" }
mockforge-grpc = { path = "../mockforge/crates/mockforge-grpc" }

Core Concepts

Configuration System

MockForge uses a hierarchical configuration system that can be built programmatically:

#![allow(unused)]
fn main() {
use mockforge_core::config::MockForgeConfig;

let config = MockForgeConfig {
    server: ServerConfig {
        http_port: Some(3000),
        ws_port: Some(3001),
        grpc_port: Some(50051),
    },
    validation: ValidationConfig {
        mode: ValidationMode::Enforce,
        aggregate_errors: false,
    },
    response: ResponseConfig {
        template_expand: true,
    },
    ..Default::default()
};
}

Template System

MockForge includes a powerful template engine for dynamic content generation:

#![allow(unused)]
fn main() {
use mockforge_core::template::{TemplateEngine, Context};

let engine = TemplateEngine::new();
let context = Context::new()
    .with_value("user_id", "12345")
    .with_value("timestamp", "2025-09-12T10:00:00Z");

let result = engine.render("User {{user_id}} logged in at {{timestamp}}", &context)?;
assert_eq!(result, "User 12345 logged in at 2025-09-12T10:00:00Z");
}

Error Handling

MockForge uses the anyhow crate for error handling:

#![allow(unused)]
fn main() {
use anyhow::{Result, Context};

fn start_server(config: &Config) -> Result<()> {
    let server = HttpServer::new(config)
        .context("Failed to create HTTP server")?;

    server.start()
        .context("Failed to start server")?;

    Ok(())
}
}

HTTP API

Basic HTTP Server

use mockforge_http::{HttpServer, HttpConfig};
use mockforge_core::config::ServerConfig;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create HTTP configuration
    let http_config = HttpConfig {
        spec_path: Some("api-spec.yaml".to_string()),
        validation_mode: ValidationMode::Warn,
        template_expand: true,
    };

    // Start HTTP server
    let mut server = HttpServer::new(http_config);
    server.start(([127, 0, 0, 1], 3000)).await?;

    println!("HTTP server running on http://localhost:3000");
    Ok(())
}

Custom Route Handlers

use mockforge_http::{HttpServer, RouteHandler};
use warp::{Filter, Reply};

struct CustomHandler;

impl RouteHandler for CustomHandler {
    fn handle(&self, path: &str, method: &str) -> Option<Box<dyn Reply>> {
        if path == "/custom" && method == "GET" {
            Some(Box::new(warp::reply::json(&serde_json::json!({
                "message": "Custom response",
                "timestamp": chrono::Utc::now()
            }))))
        } else {
            None
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let handler = CustomHandler;
    let server = HttpServer::with_handler(handler);
    server.start(([127, 0, 0, 1], 3000)).await?;
    Ok(())
}

gRPC API

Basic gRPC Server

use mockforge_grpc::{GrpcServer, GrpcConfig};
use std::path::Path;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Configure proto discovery
    let config = GrpcConfig {
        proto_dir: Path::new("proto/"),
        enable_reflection: true,
        ..Default::default()
    };

    // Start gRPC server
    let server = GrpcServer::new(config);
    server.start("127.0.0.1:50051").await?;

    println!("gRPC server running on 127.0.0.1:50051");
    Ok(())
}

Custom Service Implementation

use mockforge_grpc::{ServiceRegistry, ServiceImplementation};
use prost::Message;
use tonic::{Request, Response, Status};

// Generated from proto file
mod greeter {
    include!("generated/greeter.rs");
}

pub struct GreeterService;

#[tonic::async_trait]
impl greeter::greeter_server::Greeter for GreeterService {
    async fn say_hello(
        &self,
        request: Request<greeter::HelloRequest>,
    ) -> Result<Response<greeter::HelloReply>, Status> {
        let name = request.into_inner().name;

        let reply = greeter::HelloReply {
            message: format!("Hello, {}!", name),
            timestamp: Some(prost_types::Timestamp::from(std::time::SystemTime::now())),
        };

        Ok(Response::new(reply))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let service = GreeterService {};
    let server = GrpcServer::with_service(service);
    server.start("127.0.0.1:50051").await?;
    Ok(())
}

WebSocket API

Basic WebSocket Server

use mockforge_ws::{WebSocketServer, WebSocketConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = WebSocketConfig {
        port: 3001,
        replay_file: Some("ws-replay.jsonl".to_string()),
        ..Default::default()
    };

    let server = WebSocketServer::new(config);
    server.start().await?;

    println!("WebSocket server running on ws://localhost:3001");
    Ok(())
}

Custom Message Handler

use mockforge_ws::{WebSocketServer, MessageHandler};
use futures_util::{SinkExt, StreamExt};

struct EchoHandler;

impl MessageHandler for EchoHandler {
    async fn handle_message(&self, message: String) -> String {
        format!("Echo: {}", message)
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let handler = EchoHandler {};
    let server = WebSocketServer::with_handler(handler);
    server.start().await?;
    Ok(())
}

This Rust API reference provides the foundation for programmatic usage of MockForge. For protocol-specific details, see the HTTP, gRPC, and WebSocket API documentation.

HTTP Module

The mockforge_http crate provides comprehensive HTTP/REST API mocking capabilities with OpenAPI integration, AI-powered responses, and advanced management features.

Modules

Core Functions

build_router

#![allow(unused)]
fn main() {
pub async fn build_router(
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    failure_config: Option<FailureConfig>,
) -> Router
}

Creates a basic HTTP router with optional OpenAPI specification support.

Parameters:

  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options for request/response validation
  • failure_config: Optional failure injection configuration

Returns: Axum Router configured for HTTP mocking

Example:

#![allow(unused)]
fn main() {
use mockforge_http::build_router;
use mockforge_core::ValidationOptions;

let router = build_router(
    Some("./api.yaml".to_string()),
    Some(ValidationOptions::enforce()),
    None,
).await;
}

build_router_with_auth

#![allow(unused)]
fn main() {
pub async fn build_router_with_auth(
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    auth_config: Option<AuthConfig>,
) -> Router
}

Creates an HTTP router with authentication support.

Parameters:

  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options
  • auth_config: Authentication configuration (OAuth2, JWT, API keys)

Returns: Axum Router with authentication middleware

Example:

#![allow(unused)]
fn main() {
use mockforge_http::build_router_with_auth;
use mockforge_core::config::AuthConfig;

let auth_config = AuthConfig {
    oauth2: Some(OAuth2Config {
        client_id: "client123".to_string(),
        client_secret: "secret".to_string(),
        ..Default::default()
    }),
    ..Default::default()
};

let router = build_router_with_auth(
    Some("./api.yaml".to_string()),
    None,
    Some(auth_config),
).await;
}

build_router_with_chains

#![allow(unused)]
fn main() {
pub async fn build_router_with_chains(
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    chain_config: Option<RequestChainingConfig>,
) -> Router
}

Creates an HTTP router with request chaining support for multi-step workflows.

Parameters:

  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options
  • chain_config: Request chaining configuration

Returns: Axum Router with chaining capabilities

build_router_with_multi_tenant

#![allow(unused)]
fn main() {
pub async fn build_router_with_multi_tenant(
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    failure_config: Option<FailureConfig>,
    multi_tenant_config: Option<MultiTenantConfig>,
    route_configs: Option<Vec<RouteConfig>>,
    cors_config: Option<HttpCorsConfig>,
) -> Router
}

Creates an HTTP router with multi-tenant workspace support.

Parameters:

  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options
  • failure_config: Optional failure injection configuration
  • multi_tenant_config: Multi-tenant workspace configuration
  • route_configs: Custom route configurations
  • cors_config: CORS configuration

Returns: Axum Router with multi-tenant support

build_router_with_traffic_shaping

#![allow(unused)]
fn main() {
pub async fn build_router_with_traffic_shaping(
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    traffic_shaper: Option<TrafficShaper>,
    traffic_shaping_enabled: bool,
) -> Router
}

Creates an HTTP router with traffic shaping capabilities.

Parameters:

  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options
  • traffic_shaper: Traffic shaping configuration
  • traffic_shaping_enabled: Whether traffic shaping is active

Returns: Axum Router with traffic shaping middleware

Server Functions

serve_router

#![allow(unused)]
fn main() {
pub async fn serve_router(
    port: u16,
    app: Router,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
}

Starts the HTTP server on the specified port.

Parameters:

  • port: Port number to bind to
  • app: Axum router to serve

Returns: Result<(), Error> indicating server startup success

Errors:

  • Port binding failures
  • Server startup errors

start

#![allow(unused)]
fn main() {
pub async fn start(
    port: u16,
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
}

Convenience function to build and start an HTTP server.

Parameters:

  • port: Port number to bind to
  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options

start_with_auth_and_latency

#![allow(unused)]
fn main() {
pub async fn start_with_auth_and_latency(
    port: u16,
    spec_path: Option<String>,
    options: Option<ValidationOptions>,
    auth_config: Option<AuthConfig>,
    latency_profile: Option<LatencyProfile>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
}

Starts HTTP server with authentication and latency simulation.

Parameters:

  • port: Port number to bind to
  • spec_path: Optional path to OpenAPI specification file
  • options: Optional validation options
  • auth_config: Authentication configuration
  • latency_profile: Latency injection profile

Management API

management_router

#![allow(unused)]
fn main() {
pub fn management_router(state: ManagementState) -> Router
}

Creates a management API router for server control and monitoring.

Parameters:

  • state: Management state containing server statistics and configuration

Returns: Axum Router with management endpoints

Endpoints:

  • GET /health - Health check
  • GET /stats - Server statistics
  • GET /routes - Route information
  • GET /coverage - API coverage metrics
  • GET/POST/PUT/DELETE /mocks - Mock management

management_ws_router

#![allow(unused)]
fn main() {
pub fn ws_management_router(state: WsManagementState) -> Router
}

Creates a WebSocket management router for real-time monitoring.

Parameters:

  • state: WebSocket management state

Returns: Axum Router with WebSocket management endpoints

AI Integration

process_response_with_ai

#![allow(unused)]
fn main() {
pub async fn process_response_with_ai(
    response_body: Option<Value>,
    intelligent_config: Option<Value>,
    drift_config: Option<Value>,
) -> Result<Value>
}

Processes a response body using AI features if configured.

Parameters:

  • response_body: Base response body as JSON Value
  • intelligent_config: Intelligent mock generation configuration
  • drift_config: Data drift simulation configuration

Returns: Result<Value, Error> with processed response

Example:

#![allow(unused)]
fn main() {
use mockforge_http::process_response_with_ai;
use serde_json::json;

let config = json!({
    "enabled": true,
    "prompt": "Generate realistic user data"
});

let response = process_response_with_ai(
    Some(json!({"name": "John"})),
    Some(config),
    None,
).await?;
}

Data Structures

HttpServerState

#![allow(unused)]
fn main() {
pub struct HttpServerState {
    pub routes: Vec<RouteInfo>,
    pub rate_limiter: Option<Arc<GlobalRateLimiter>>,
}
}

Shared state for HTTP server route information and rate limiting.

Fields:

  • routes: Vector of route information
  • rate_limiter: Optional global rate limiter

Methods:

#![allow(unused)]
fn main() {
impl HttpServerState {
    pub fn new() -> Self
    pub fn with_routes(routes: Vec<RouteInfo>) -> Self
    pub fn with_rate_limiter(rate_limiter: Arc<GlobalRateLimiter>) -> Self
}
}

RouteInfo

#![allow(unused)]
fn main() {
pub struct RouteInfo {
    pub method: String,
    pub path: String,
    pub operation_id: Option<String>,
    pub summary: Option<String>,
    pub description: Option<String>,
    pub parameters: Vec<String>,
}
}

Information about an HTTP route.

Fields:

  • method: HTTP method (GET, POST, etc.)
  • path: Route path pattern
  • operation_id: Optional OpenAPI operation ID
  • summary: Optional route summary
  • description: Optional route description
  • parameters: List of parameter names

ManagementState

#![allow(unused)]
fn main() {
pub struct ManagementState {
    pub mocks: Arc<RwLock<Vec<MockConfig>>>,
    pub spec: Option<Arc<OpenApiSpec>>,
    pub spec_path: Option<String>,
    pub port: u16,
    pub start_time: Instant,
    pub request_counter: Arc<RwLock<u64>>,
}
}

State for the management API.

Fields:

  • mocks: Thread-safe vector of mock configurations
  • spec: Optional OpenAPI specification
  • spec_path: Optional path to spec file
  • port: Server port
  • start_time: Server startup timestamp
  • request_counter: Request counter for statistics

Methods:

#![allow(unused)]
fn main() {
impl ManagementState {
    pub fn new(
        spec: Option<Arc<OpenApiSpec>>,
        spec_path: Option<String>,
        port: u16,
    ) -> Self
}
}

MockConfig

#![allow(unused)]
fn main() {
pub struct MockConfig {
    pub id: String,
    pub name: String,
    pub method: String,
    pub path: String,
    pub response: MockResponse,
    pub enabled: bool,
    pub latency_ms: Option<u64>,
    pub status_code: Option<u16>,
}
}

Configuration for a mock endpoint.

Fields:

  • id: Unique mock identifier
  • name: Human-readable name
  • method: HTTP method
  • path: Route path
  • response: Mock response configuration
  • enabled: Whether mock is active
  • latency_ms: Optional latency injection
  • status_code: Optional status code override

MockResponse

#![allow(unused)]
fn main() {
pub struct MockResponse {
    pub body: Value,
    pub headers: Option<HashMap<String, String>>,
}
}

Mock response configuration.

Fields:

  • body: JSON response body
  • headers: Optional HTTP headers

ServerStats

#![allow(unused)]
fn main() {
pub struct ServerStats {
    pub uptime_seconds: u64,
    pub total_requests: u64,
    pub active_mocks: usize,
    pub enabled_mocks: usize,
    pub registered_routes: usize,
}
}

Server statistics.

Fields:

  • uptime_seconds: Server uptime in seconds
  • total_requests: Total requests processed
  • active_mocks: Number of configured mocks
  • enabled_mocks: Number of enabled mocks
  • registered_routes: Number of registered routes

ServerConfig

#![allow(unused)]
fn main() {
pub struct ServerConfig {
    pub version: String,
    pub port: u16,
    pub has_openapi_spec: bool,
    pub spec_path: Option<String>,
}
}

Server configuration information.

Fields:

  • version: MockForge version
  • port: Server port
  • has_openapi_spec: Whether OpenAPI spec is loaded
  • spec_path: Optional path to spec file

AI Types

AiResponseConfig

#![allow(unused)]
fn main() {
pub struct AiResponseConfig {
    pub enabled: bool,
    pub rag_config: RagConfig,
    pub prompt: String,
    pub schema: Option<Value>,
}
}

Configuration for AI-powered response generation.

Fields:

  • enabled: Whether AI responses are enabled
  • rag_config: RAG (Retrieval-Augmented Generation) configuration
  • prompt: AI generation prompt
  • schema: Optional response schema

AiResponseHandler

#![allow(unused)]
fn main() {
pub struct AiResponseHandler { /* fields omitted */ }
}

Handler for AI-powered response generation.

Methods:

#![allow(unused)]
fn main() {
impl AiResponseHandler {
    pub fn new(
        intelligent_config: Option<IntelligentMockConfig>,
        drift_config: Option<DataDriftConfig>,
    ) -> Result<Self>

    pub fn is_enabled(&self) -> bool

    pub async fn generate_response(&mut self, base_response: Option<Value>) -> Result<Value>

    pub async fn reset_drift(&self)
}
}

Coverage Types

CoverageReport

#![allow(unused)]
fn main() {
pub struct CoverageReport {
    pub routes: HashMap<String, RouteCoverage>,
    pub total_routes: usize,
    pub covered_routes: usize,
    pub coverage_percentage: f64,
}
}

API coverage report.

Fields:

  • routes: Coverage data per route
  • total_routes: Total number of routes
  • covered_routes: Number of covered routes
  • coverage_percentage: Coverage percentage (0.0-100.0)

RouteCoverage

#![allow(unused)]
fn main() {
pub struct RouteCoverage {
    pub method: String,
    pub path: String,
    pub methods: HashMap<String, MethodCoverage>,
    pub total_requests: u64,
    pub covered_methods: usize,
}
}

Coverage information for a specific route.

Fields:

  • method: HTTP method
  • path: Route path
  • methods: Coverage per HTTP method
  • total_requests: Total requests to this route
  • covered_methods: Number of methods with coverage

MethodCoverage

#![allow(unused)]
fn main() {
pub struct MethodCoverage {
    pub request_count: u64,
    pub response_codes: HashMap<u16, u64>,
    pub last_request: Option<DateTime<Utc>>,
}
}

Coverage information for a specific HTTP method.

Fields:

  • request_count: Number of requests
  • response_codes: Response code distribution
  • last_request: Timestamp of last request

Coverage Functions

calculate_coverage

#![allow(unused)]
fn main() {
pub fn calculate_coverage(
    routes: &[RouteInfo],
    request_logs: &[RequestLogEntry],
) -> CoverageReport
}

Calculates API coverage from route information and request logs.

Parameters:

  • routes: Available routes
  • request_logs: Historical request logs

Returns: CoverageReport with coverage statistics

get_coverage_handler

#![allow(unused)]
fn main() {
pub async fn get_coverage_handler(State(state): State<HttpServerState>) -> Json<Value>
}

Axum handler for coverage endpoint.

Returns: JSON response with coverage data

Middleware Functions

collect_http_metrics

#![allow(unused)]
fn main() {
pub fn collect_http_metrics(request: &Request, response: &Response, duration: Duration)
}

Collects HTTP metrics for observability.

Parameters:

  • request: HTTP request
  • response: HTTP response
  • duration: Request processing duration

http_tracing_middleware

#![allow(unused)]
fn main() {
pub fn http_tracing_middleware(
    request: Request,
    next: Next,
) -> impl Future<Output = Response>
}

Middleware for HTTP request tracing.

Parameters:

  • request: Incoming HTTP request
  • next: Next middleware in chain

Returns: Future resolving to HTTP response

Error Types

All functions return Result<T, Box<dyn std::error::Error + Send + Sync>> for error handling. Common errors include:

  • File I/O errors (spec file reading)
  • JSON parsing errors
  • Server binding errors
  • Validation errors
  • AI service errors

Constants

  • DEFAULT_RATE_LIMIT_RPM: Default requests per minute (1000)
  • DEFAULT_RATE_LIMIT_BURST: Default burst size (2000)

Feature Flags

  • data-faker: Enables rich data generation features

Examples

Basic HTTP Server

use mockforge_http::build_router;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let router = build_router(
        Some("./api.yaml".to_string()),
        None,
        None,
    ).await;

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, router).await?;
    Ok(())
}

Server with Management API

use mockforge_http::{build_router, management_router, ManagementState};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build main router
    let app = build_router(None, None, None).await;

    // Add management API
    let mgmt_state = ManagementState::new(None, None, 3000);
    let mgmt_router = management_router(mgmt_state);

    let app = app.nest("/__mockforge", mgmt_router);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

AI-Powered Responses

use mockforge_http::{AiResponseConfig, process_response_with_ai};
use mockforge_data::RagConfig;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ai_config = AiResponseConfig {
        enabled: true,
        rag_config: RagConfig {
            provider: "openai".to_string(),
            model: "gpt-3.5-turbo".to_string(),
            api_key: Some("sk-...".to_string()),
            ..Default::default()
        },
        prompt: "Generate realistic user data".to_string(),
        schema: None,
    };

    let response = process_response_with_ai(
        Some(serde_json::json!({"id": 1})),
        Some(serde_json::to_value(ai_config)?),
        None,
    ).await?;

    println!("AI response: {}", response);
    Ok(())
}

gRPC Module

The mockforge_grpc crate provides dynamic gRPC service discovery and mocking with HTTP bridge capabilities.

Modules

Core Functions

start

#![allow(unused)]
fn main() {
pub async fn start(port: u16) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
}

Starts a gRPC server with default configuration on the specified port.

Parameters:

  • port: Port number to bind the gRPC server to

Returns: Result<(), Error> indicating server startup success

Example:

use mockforge_grpc::start;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    start(50051).await?;
    Ok(())
}

start_with_config

#![allow(unused)]
fn main() {
pub async fn start_with_config(
    port: u16,
    latency_profile: Option<LatencyProfile>,
    config: DynamicGrpcConfig,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
}

Starts a gRPC server with custom configuration and optional latency simulation.

Parameters:

  • port: Port number to bind the gRPC server to
  • latency_profile: Optional latency injection profile
  • config: Dynamic gRPC configuration

Returns: Result<(), Error> indicating server startup success

Example:

#![allow(unused)]
fn main() {
use mockforge_grpc::{start_with_config, DynamicGrpcConfig};
use mockforge_core::LatencyProfile;

let config = DynamicGrpcConfig {
    proto_dir: "./proto".to_string(),
    enable_reflection: true,
    ..Default::default()
};

start_with_config(50051, Some(LatencyProfile::normal()), config).await?;
}

Configuration Types

DynamicGrpcConfig

#![allow(unused)]
fn main() {
pub struct DynamicGrpcConfig {
    pub proto_dir: String,
    pub enable_reflection: bool,
    pub excluded_services: Vec<String>,
    pub http_bridge: Option<HttpBridgeConfig>,
}
}

Configuration for dynamic gRPC service discovery.

Fields:

  • proto_dir: Directory containing .proto files (default: “proto”)
  • enable_reflection: Whether to enable gRPC reflection (default: false)
  • excluded_services: List of services to exclude from discovery
  • http_bridge: Optional HTTP bridge configuration

Methods:

#![allow(unused)]
fn main() {
impl DynamicGrpcConfig {
    pub fn default() -> Self
}
}

Example:

#![allow(unused)]
fn main() {
let config = DynamicGrpcConfig {
    proto_dir: "./my-protos".to_string(),
    enable_reflection: true,
    excluded_services: vec!["HealthService".to_string()],
    http_bridge: Some(HttpBridgeConfig {
        enabled: true,
        port: 8080,
        generate_openapi: true,
    }),
};
}

HttpBridgeConfig

#![allow(unused)]
fn main() {
pub struct HttpBridgeConfig {
    pub enabled: bool,
    pub port: u16,
    pub generate_openapi: bool,
    pub cors_enabled: bool,
}
}

Configuration for HTTP bridge functionality.

Fields:

  • enabled: Whether HTTP bridge is enabled (default: true)
  • port: HTTP server port (default: 8080)
  • generate_openapi: Whether to generate OpenAPI specs (default: true)
  • cors_enabled: Whether CORS is enabled (default: false)

Methods:

#![allow(unused)]
fn main() {
impl HttpBridgeConfig {
    pub fn default() -> Self
}
}

Service Registry

ServiceRegistry

#![allow(unused)]
fn main() {
pub struct ServiceRegistry { /* fields omitted */ }
}

Registry containing discovered gRPC services.

Methods:

#![allow(unused)]
fn main() {
impl ServiceRegistry {
    pub fn new() -> Self
    pub fn with_descriptor_pool(descriptor_pool: DescriptorPool) -> Self
    pub fn descriptor_pool(&self) -> &DescriptorPool
    pub fn register(&mut self, name: String, service: DynamicGrpcService)
    pub fn get(&self, name: &str) -> Option<&Arc<DynamicGrpcService>>
    pub fn service_names(&self) -> Vec<String>
}
}

Example:

#![allow(unused)]
fn main() {
use mockforge_grpc::ServiceRegistry;

let mut registry = ServiceRegistry::new();
registry.register("MyService".to_string(), dynamic_service);
println!("Registered services: {:?}", registry.service_names());
}

Dynamic Service Types

DynamicGrpcService

#![allow(unused)]
fn main() {
pub struct DynamicGrpcService { /* fields omitted */ }
}

Dynamically generated gRPC service implementation.

Methods:

#![allow(unused)]
fn main() {
impl DynamicGrpcService {
    pub fn new(
        proto_service: ProtoService,
        config: Option<ServiceConfig>,
    ) -> Self
}
}

ProtoService

#![allow(unused)]
fn main() {
pub struct ProtoService {
    pub name: String,
    pub methods: HashMap<String, ProtoMethod>,
    pub package: String,
}
}

Parsed protobuf service definition.

Fields:

  • name: Service name
  • methods: Map of method names to method definitions
  • package: Protobuf package name

ProtoMethod

#![allow(unused)]
fn main() {
pub struct ProtoMethod {
    pub name: String,
    pub input_type: String,
    pub output_type: String,
    pub is_client_streaming: bool,
    pub is_server_streaming: bool,
}
}

Parsed protobuf method definition.

Fields:

  • name: Method name
  • input_type: Input message type name
  • output_type: Output message type name
  • is_client_streaming: Whether method accepts client streaming
  • is_server_streaming: Whether method returns server streaming

Mock Response Types

MockResponse

#![allow(unused)]
fn main() {
pub enum MockResponse {
    Unary(Value),
    ServerStream(Vec<Value>),
    ClientStream(Value),
    BidiStream(Vec<Value>),
}
}

Mock response types for different gRPC method patterns.

Variants:

  • Unary(Value): Single request-response
  • ServerStream(Vec<Value>): Server streaming response
  • ClientStream(Value): Client streaming response
  • BidiStream(Vec<Value>): Bidirectional streaming

Reflection Types

MockReflectionProxy

#![allow(unused)]
fn main() {
pub struct MockReflectionProxy { /* fields omitted */ }
}

Proxy for gRPC reflection protocol.

Methods:

#![allow(unused)]
fn main() {
impl MockReflectionProxy {
    pub async fn new(
        config: ProxyConfig,
        registry: Arc<ServiceRegistry>,
    ) -> Result<Self>
}
}

ReflectionProxy

#![allow(unused)]
fn main() {
pub trait ReflectionProxy {
    fn list_services(&self) -> Vec<String>;
    fn get_service_descriptor(&self, service_name: &str) -> Option<&prost_reflect::ServiceDescriptor>;
    fn get_method_descriptor(&self, service_name: &str, method_name: &str) -> Option<&prost_reflect::MethodDescriptor>;
}
}

Trait for gRPC reflection functionality.

ProxyConfig

#![allow(unused)]
fn main() {
pub struct ProxyConfig {
    pub max_message_size: usize,
    pub connection_timeout: Duration,
    pub request_timeout: Duration,
}
}

Configuration for reflection proxy.

Fields:

  • max_message_size: Maximum message size in bytes (default: 4MB)
  • connection_timeout: Connection timeout duration
  • request_timeout: Request timeout duration

Proto Parser

ProtoParser

#![allow(unused)]
fn main() {
pub struct ProtoParser { /* fields omitted */ }
}

Parser for protobuf files.

Methods:

#![allow(unused)]
fn main() {
impl ProtoParser {
    pub fn new() -> Self
    pub async fn parse_directory(&mut self, dir: &str) -> Result<()>
    pub fn services(&self) -> &HashMap<String, ProtoService>
    pub fn into_pool(self) -> DescriptorPool
}
}

Example:

#![allow(unused)]
fn main() {
use mockforge_grpc::dynamic::proto_parser::ProtoParser;

let mut parser = ProtoParser::new();
parser.parse_directory("./proto").await?;
let services = parser.services();
println!("Found {} services", services.len());
}

Discovery Functions

discover_services

#![allow(unused)]
fn main() {
pub async fn discover_services(
    config: &DynamicGrpcConfig,
) -> Result<ServiceRegistry, Box<dyn std::error::Error + Send + Sync>>
}

Discovers and registers gRPC services from proto files.

Parameters:

  • config: Discovery configuration

Returns: Result<ServiceRegistry, Error> with discovered services

Example:

#![allow(unused)]
fn main() {
use mockforge_grpc::{discover_services, DynamicGrpcConfig};

let config = DynamicGrpcConfig {
    proto_dir: "./proto".to_string(),
    ..Default::default()
};

let registry = discover_services(&config).await?;
println!("Discovered services: {:?}", registry.service_names());
}

Generated Types

Greeter Service

#![allow(unused)]
fn main() {
pub mod generated {
    pub mod greeter_server {
        pub trait Greeter: Send + Sync + 'static {
            type SayHelloStreamStream: Stream<Item = Result<HelloReply, Status>> + Send + 'static;

            async fn say_hello(
                &self,
                request: Request<HelloRequest>,
            ) -> Result<Response<HelloReply>, Status>;

            async fn say_hello_stream(
                &self,
                request: Request<HelloRequest>,
            ) -> Result<Response<Self::SayHelloStreamStream>, Status>;

            async fn say_hello_client_stream(
                &self,
                request: Request<Streaming<HelloRequest>>,
            ) -> Result<Response<HelloReply>, Status>;

            async fn chat(
                &self,
                request: Request<Streaming<HelloRequest>>,
            ) -> Result<Response<Self::ChatStream>, Status>;
        }
    }
}
}

Generated gRPC service trait with all streaming patterns.

Message Types

HelloRequest

#![allow(unused)]
fn main() {
pub struct HelloRequest {
    pub name: String,
}
}

Request message for greeting service.

Fields:

  • name: Name to greet

HelloReply

#![allow(unused)]
fn main() {
pub struct HelloReply {
    pub message: String,
    pub metadata: Option<HashMap<String, String>>,
    pub items: Vec<String>,
}
}

Response message for greeting service.

Fields:

  • message: Greeting message
  • metadata: Optional metadata map
  • items: Optional list of items

Error Handling

All functions return Result<T, Box<dyn std::error::Error + Send + Sync>>. Common errors include:

  • File I/O errors (proto file reading)
  • Protobuf parsing errors
  • Server binding errors
  • Reflection setup errors
  • HTTP bridge configuration errors

Constants

  • DEFAULT_MAX_MESSAGE_SIZE: Default maximum message size (4MB)

Feature Flags

  • data-faker: Enables advanced data synthesis features

Examples

Basic gRPC Server

use mockforge_grpc::start;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Starts server on port 50051 with default config
    // Automatically discovers services from ./proto directory
    start(50051).await?;
    Ok(())
}

Server with Reflection

use mockforge_grpc::{start_with_config, DynamicGrpcConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let config = DynamicGrpcConfig {
        proto_dir: "./proto".to_string(),
        enable_reflection: true,  // Enable gRPC reflection
        ..Default::default()
    };

    start_with_config(50051, None, config).await?;

    // Now you can use grpcurl:
    // grpcurl -plaintext localhost:50051 list
    // grpcurl -plaintext localhost:50051 describe MyService
    Ok(())
}

Server with HTTP Bridge

use mockforge_grpc::{start_with_config, DynamicGrpcConfig};
use mockforge_grpc::dynamic::http_bridge::HttpBridgeConfig;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let config = DynamicGrpcConfig {
        proto_dir: "./proto".to_string(),
        http_bridge: Some(HttpBridgeConfig {
            enabled: true,
            port: 8080,
            generate_openapi: true,
        }),
        ..Default::default()
    };

    start_with_config(50051, None, config).await?;

    // gRPC available on localhost:50051
    // REST API available on localhost:8080
    // OpenAPI docs at http://localhost:8080/api/docs
    Ok(())
}

Manual Service Discovery

use mockforge_grpc::{discover_services, DynamicGrpcConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let config = DynamicGrpcConfig {
        proto_dir: "./proto".to_string(),
        excluded_services: vec!["HealthService".to_string()],
        ..Default::default()
    };

    let registry = discover_services(&config).await?;

    println!("Discovered services:");
    for service_name in registry.service_names() {
        println!("  - {}", service_name);
    }

    // Access service descriptors
    if let Some(descriptor) = registry.descriptor_pool().get_service_by_name("MyService") {
        println!("Service methods:");
        for method in descriptor.methods() {
            println!("  - {}", method.name());
        }
    }

    Ok(())
}

Custom Service Implementation

use mockforge_grpc::dynamic::service_generator::DynamicGrpcService;
use mockforge_grpc::dynamic::proto_parser::{ProtoParser, ProtoService};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Parse proto files
    let mut parser = ProtoParser::new();
    parser.parse_directory("./proto").await?;

    // Get a specific service
    if let Some(proto_service) = parser.services().get("MyService") {
        // Create dynamic service
        let dynamic_service = DynamicGrpcService::new(proto_service.clone(), None);

        // The service will automatically handle all RPC methods
        // with mock responses based on the protobuf definitions
    }

    Ok(())
}

Using gRPC Reflection

use mockforge_grpc::reflection::{MockReflectionProxy, ProxyConfig};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let config = DynamicGrpcConfig {
        proto_dir: "./proto".to_string(),
        enable_reflection: true,
        ..Default::default()
    };

    let registry = discover_services(&config).await?;
    let registry_arc = Arc::new(registry);

    let proxy_config = ProxyConfig::default();
    let reflection_proxy = MockReflectionProxy::new(proxy_config, registry_arc).await?;

    // The reflection proxy enables:
    // - Service listing: reflection_proxy.list_services()
    // - Service descriptors: reflection_proxy.get_service_descriptor("MyService")
    // - Method descriptors: reflection_proxy.get_method_descriptor("MyService", "MyMethod")

    Ok(())
}

WebSocket Module

The mockforge_ws crate provides comprehensive WebSocket mocking with replay, proxy, and AI-powered event generation capabilities.

Modules

Core Functions

router

#![allow(unused)]
fn main() {
pub fn router() -> Router
}

Creates a basic WebSocket router with echo functionality.

Returns: Axum Router configured for WebSocket connections

Example:

#![allow(unused)]
fn main() {
use mockforge_ws::router;

let app = router();
// Routes WebSocket connections to /ws
}

router_with_latency

#![allow(unused)]
fn main() {
pub fn router_with_latency(latency_injector: LatencyInjector) -> Router
}

Creates a WebSocket router with latency simulation.

Parameters:

  • latency_injector: Latency injection configuration

Returns: Axum Router with latency simulation

Example:

#![allow(unused)]
fn main() {
use mockforge_ws::router_with_latency;
use mockforge_core::{LatencyProfile, latency::LatencyInjector};

let latency = LatencyProfile::slow(); // 300-800ms
let injector = LatencyInjector::new(latency, Default::default());
let app = router_with_latency(injector);
}

router_with_proxy

#![allow(unused)]
fn main() {
pub fn router_with_proxy(proxy_handler: WsProxyHandler) -> Router
}

Creates a WebSocket router with proxy capabilities.

Parameters:

  • proxy_handler: WebSocket proxy handler configuration

Returns: Axum Router with proxy functionality

Example:

#![allow(unused)]
fn main() {
use mockforge_ws::router_with_proxy;
use mockforge_core::{WsProxyConfig, WsProxyHandler};

let proxy_config = WsProxyConfig {
    upstream_url: "wss://api.example.com/ws".to_string(),
    should_proxy: true,
    ..Default::default()
};
let proxy = WsProxyHandler::new(proxy_config);
let app = router_with_proxy(proxy);
}

Server Functions

start_with_latency

#![allow(unused)]
fn main() {
pub async fn start_with_latency(
    port: u16,
    latency: Option<LatencyProfile>,
) -> Result<(), Box<dyn std::error::Error>>
}

Starts a WebSocket server with optional latency simulation.

Parameters:

  • port: Port number to bind to
  • latency: Optional latency profile

Returns: Result<(), Error> indicating server startup success

Example:

#![allow(unused)]
fn main() {
use mockforge_ws::start_with_latency;
use mockforge_core::LatencyProfile;

start_with_latency(3001, Some(LatencyProfile::normal())).await?;
}

AI Event Generation

AiEventGenerator

#![allow(unused)]
fn main() {
pub struct AiEventGenerator { /* fields omitted */ }
}

Generator for AI-powered WebSocket event streams.

Methods:

#![allow(unused)]
fn main() {
impl AiEventGenerator {
    pub fn new(config: ReplayAugmentationConfig) -> Result<Self>

    pub async fn stream_events(
        &self,
        socket: WebSocket,
        max_events: Option<usize>,
    )

    pub async fn stream_events_with_rate(
        &self,
        socket: WebSocket,
        max_events: Option<usize>,
        events_per_second: f64,
    )
}
}

Example:

#![allow(unused)]
fn main() {
use mockforge_ws::AiEventGenerator;
use mockforge_data::ReplayAugmentationConfig;

let config = ReplayAugmentationConfig {
    narrative: "Simulate stock market trading".to_string(),
    ..Default::default()
};

let generator = AiEventGenerator::new(config)?;
generator.stream_events(socket, Some(100)).await?;
}

WebSocketAiConfig

#![allow(unused)]
fn main() {
pub struct WebSocketAiConfig {
    pub enabled: bool,
    pub replay: Option<ReplayAugmentationConfig>,
    pub max_events: Option<usize>,
}
}

Configuration for WebSocket AI features.

Fields:

  • enabled: Whether AI features are enabled
  • replay: Optional replay augmentation configuration
  • max_events: Maximum number of events to generate

Tracing Functions

create_ws_connection_span

#![allow(unused)]
fn main() {
pub fn create_ws_connection_span(request: &Request) -> Span
}

Creates an OpenTelemetry span for WebSocket connection establishment.

Parameters:

  • request: HTTP request that initiated the WebSocket connection

Returns: OpenTelemetry Span for connection tracking

create_ws_message_span

#![allow(unused)]
fn main() {
pub fn create_ws_message_span(message_size: usize, direction: &str) -> Span
}

Creates an OpenTelemetry span for WebSocket message processing.

Parameters:

  • message_size: Size of the message in bytes
  • direction: Message direction (“in” or “out”)

Returns: OpenTelemetry Span for message tracking

record_ws_connection_success

#![allow(unused)]
fn main() {
pub fn record_ws_connection_success(span: &Span)
}

Records successful WebSocket connection establishment.

Parameters:

  • span: Connection span to record success on

record_ws_message_success

#![allow(unused)]
fn main() {
pub fn record_ws_message_success(span: &Span, message_size: usize)
}

Records successful WebSocket message processing.

Parameters:

  • span: Message span to record success on
  • message_size: Size of processed message

record_ws_error

#![allow(unused)]
fn main() {
pub fn record_ws_error(span: &Span, error: &str)
}

Records WebSocket error.

Parameters:

  • span: Span to record error on
  • error: Error description

Template Expansion

Token Expansion Functions

The crate includes internal template expansion functionality for replay files:

#![allow(unused)]
fn main() {
fn expand_tokens(text: &str) -> String
}

Expands template tokens in replay file content.

Supported Tokens:

  • {{uuid}}: Generates random UUID
  • {{now}}: Current timestamp in RFC3339 format
  • {{now+1m}}: Timestamp 1 minute from now
  • {{now+1h}}: Timestamp 1 hour from now
  • {{randInt min max}}: Random integer between min and max

Example:

#![allow(unused)]
fn main() {
let text = "Hello {{uuid}} at {{now}}";
let expanded = expand_tokens(text);
// Result: "Hello 550e8400-e29b-41d4-a716-446655440000 at 2024-01-15T10:30:00Z"
}

Internal Types

WebSocket Message Handling

The crate uses Axum’s WebSocket types internally:

#![allow(unused)]
fn main() {
use axum::extract::ws::{Message, WebSocket, WebSocketUpgrade};
}

Message Types:

  • Message::Text(String): Text message
  • Message::Binary(Vec<u8>): Binary message
  • Message::Close(Option<CloseFrame>): Connection close
  • Message::Ping(Vec<u8>): Ping message
  • Message::Pong(Vec<u8>): Pong message

Error Handling

All public functions return Result<T, Box<dyn std::error::Error>>. Common errors include:

  • Server binding errors
  • WebSocket protocol errors
  • File I/O errors (for replay files)
  • AI service errors
  • Template expansion errors

Constants

  • Default WebSocket path: /ws
  • Default server port: 3001

Feature Flags

  • data-faker: Enables rich data generation features

Examples

Basic WebSocket Server

use mockforge_ws::router;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = router();

    let addr = "0.0.0.0:3001".parse()?;
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;
    Ok(())
}

Server with Latency Simulation

use mockforge_ws::start_with_latency;
use mockforge_core::LatencyProfile;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Add 50-200ms latency to all messages
    start_with_latency(3001, Some(LatencyProfile::normal())).await?;
    Ok(())
}

Proxy Server

use mockforge_ws::router_with_proxy;
use mockforge_core::{WsProxyConfig, WsProxyHandler};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let proxy_config = WsProxyConfig {
        upstream_url: "wss://echo.websocket.org".to_string(),
        should_proxy: true,
        message_transform: None,
    };

    let proxy = WsProxyHandler::new(proxy_config);
    let app = router_with_proxy(proxy);

    let addr = "0.0.0.0:3001".parse()?;
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;
    Ok(())
}

Replay Mode

use mockforge_ws::router;

// Set replay file via environment variable
std::env::set_var("MOCKFORGE_WS_REPLAY_FILE", "./replay.jsonl");

// Enable template expansion
std::env::set_var("MOCKFORGE_RESPONSE_TEMPLATE_EXPAND", "1");

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = router();

    let addr = "0.0.0.0:3001".parse()?;
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;
    Ok(())
}

AI Event Generation

#![allow(unused)]
fn main() {
use mockforge_ws::AiEventGenerator;
use mockforge_data::ReplayAugmentationConfig;
use axum::extract::ws::WebSocket;

async fn handle_ai_events(mut socket: WebSocket) {
    let config = ReplayAugmentationConfig {
        narrative: "Simulate a live chat conversation with multiple users".to_string(),
        event_count: 50,
        provider: "openai".to_string(),
        ..Default::default()
    };

    let generator = AiEventGenerator::new(config)?;
    generator.stream_events_with_rate(socket, None, 2.0).await?; // 2 events/sec
}
}

Custom WebSocket Handler

#![allow(unused)]
fn main() {
use axum::{
    extract::ws::{WebSocket, WebSocketUpgrade},
    response::IntoResponse,
};

async fn custom_ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
    ws.on_upgrade(|socket| handle_custom_socket(socket))
}

async fn handle_custom_socket(mut socket: WebSocket) {
    while let Some(msg) = socket.recv().await {
        match msg {
            Ok(axum::extract::ws::Message::Text(text)) => {
                // Process text message
                let response = format!("Echo: {}", text);
                if socket.send(axum::extract::ws::Message::Text(response.into())).await.is_err() {
                    break;
                }
            }
            Ok(axum::extract::ws::Message::Close(_)) => {
                break;
            }
            Err(e) => {
                eprintln!("WebSocket error: {}", e);
                break;
            }
            _ => {}
        }
    }
}
}

Tracing Integration

#![allow(unused)]
fn main() {
use mockforge_ws::{create_ws_connection_span, record_ws_connection_success};
use axum::extract::ws::WebSocketUpgrade;

async fn traced_ws_handler(
    ws: WebSocketUpgrade,
    request: axum::http::Request<axum::body::Body>,
) -> impl IntoResponse {
    // Create connection span
    let span = create_ws_connection_span(&request);

    // Record successful connection
    record_ws_connection_success(&span);

    ws.on_upgrade(|socket| handle_socket_with_tracing(socket, span))
}

async fn handle_socket_with_tracing(mut socket: WebSocket, connection_span: tracing::Span) {
    let _guard = connection_span.enter();

    while let Some(msg) = socket.recv().await {
        match msg {
            Ok(axum::extract::ws::Message::Text(text)) => {
                let message_span = create_ws_message_span(text.len(), "in");
                let _msg_guard = message_span.enter();

                // Process message...

                record_ws_message_success(&message_span, text.len());
            }
            // ... other message types
        }
    }
}
}

Replay File Format

Replay files use JSON Lines format with the following structure:

{"ts":0,"dir":"out","text":"HELLO {{uuid}}","waitFor":"^CLIENT_READY$"}
{"ts":10,"dir":"out","text":"{\"type\":\"welcome\",\"sessionId\":\"{{uuid}}\"}"}
{"ts":20,"dir":"out","text":"{\"data\":{{randInt 1 100}}}","waitFor":"^ACK$"}

Fields:

  • ts: Timestamp offset in milliseconds
  • dir: Direction (“in” for received, “out” for sent)
  • text: Message content (supports template expansion)
  • waitFor: Optional regex pattern to wait for before sending

Environment Variables

  • MOCKFORGE_WS_REPLAY_FILE: Path to replay file for replay mode
  • MOCKFORGE_RESPONSE_TEMPLATE_EXPAND: Enable template expansion (“1” or “true”)

Integration with MockForge Core

The WebSocket crate integrates with core MockForge functionality:

  • Latency Injection: Uses LatencyInjector for network simulation
  • Proxy Handler: Uses WsProxyHandler for upstream forwarding
  • Metrics: Integrates with global metrics registry
  • Tracing: Uses OpenTelemetry for distributed tracing
  • Data Generation: Supports AI-powered content generation

Development Setup

This guide helps contributors get started with MockForge development, including environment setup, development workflow, and project structure.

Prerequisites

Before contributing to MockForge, ensure you have the following installed:

Required Tools

  • Rust: Version 1.70.0 or later
  • Cargo: Included with Rust
  • Git: For version control
  • C/C++ Compiler: For native dependencies
  • Docker: For containerized development and testing
  • Visual Studio Code or IntelliJ/CLion with Rust plugins
  • cargo-watch for automatic rebuilds
  • cargo-edit for dependency management
  • cargo-audit for security scanning
  • mdbook for documentation development

Environment Setup

1. Install Rust

# Install Rust using rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Add Cargo to PATH
source $HOME/.cargo/env

# Verify installation
rustc --version
cargo --version

2. Clone the Repository

# Clone with SSH (recommended for contributors)
git clone [email protected]:SaaSy-Solutions/mockforge.git

# Or with HTTPS
git clone https://github.com/SaaSy-Solutions/mockforge.git

cd mockforge

# Initialize submodules if any
git submodule update --init --recursive

3. Install Development Tools

# Install cargo-watch for automatic rebuilds
cargo install cargo-watch

# Install cargo-edit for dependency management
cargo install cargo-edit

# Install cargo-audit for security scanning
cargo install cargo-audit

# Install mdbook for documentation
cargo install mdbook mdbook-linkcheck mdbook-toc

# Install additional development tools
cargo install cargo-tarpaulin cargo-udeps cargo-outdated

4. Verify Setup

# Build the project
cargo build

# Run tests
cargo test

# Check code quality
cargo clippy
cargo fmt --check

Development Workflow

Daily Development

  1. Create a feature branch:

    git checkout -b feature/your-feature-name
    
  2. Make changes with frequent testing:

    # Run tests automatically on changes
    cargo watch -x test
    
    # Or build automatically
    cargo watch -x build
    
  3. Follow code quality standards:

    # Format code
    cargo fmt
    
    # Lint code
    cargo clippy -- -W clippy::pedantic
    
    # Run security audit
    cargo audit
    
  4. Write tests for new functionality:

    # Add unit tests
    cargo test --lib
    
    # Add integration tests
    cargo test --test integration
    

IDE Configuration

Visual Studio Code

  1. Install extensions:

    • rust-lang.rust-analyzer - Rust language support
    • ms-vscode.vscode-json - JSON support
    • redhat.vscode-yaml - YAML support
    • ms-vscode.vscode-docker - Docker support
  2. Recommended settings in .vscode/settings.json:

    {
      "rust-analyzer.checkOnSave.command": "clippy",
      "rust-analyzer.cargo.allFeatures": true,
      "editor.formatOnSave": true,
      "editor.codeActionsOnSave": {
        "source.fixAll": "explicit"
      }
    }
    

IntelliJ/CLion

  1. Install Rust plugin from marketplace
  2. Enable external linter (clippy)
  3. Configure code style to match project standards

Pre-commit Setup

Install pre-commit hooks to ensure code quality:

# Install pre-commit if not already installed
pip install pre-commit

# Install all hook types (pre-commit + commit-msg + pre-push) in one step
./scripts/setup-hooks.sh

# Run on all files
pre-commit run --all-files

The pre-push hook runs the publish-list drift guard (scripts/check-publish-drift.sh): it blocks a push when a publishable workspace member is missing from scripts/publish-crates.sh, the failure mode that breaks a release when publish-crates.sh later can’t resolve the missing dependency on crates.io.

Project Structure

mockforge/
├── crates/                    # Rust crates
│   ├── mockforge-cli/        # Command-line interface
│   ├── mockforge-core/       # Shared core functionality
│   ├── mockforge-http/       # HTTP REST API mocking
│   ├── mockforge-ws/         # WebSocket connection mocking
│   ├── mockforge-grpc/       # gRPC service mocking
│   ├── mockforge-data/       # Synthetic data generation
│   └── mockforge-ui/         # Web-based admin interface
├── docs/                     # Technical documentation
├── examples/                 # Usage examples
├── book/                     # User documentation (mdBook)
│   └── src/
├── fixtures/                 # Test fixtures
├── scripts/                  # Development scripts
├── tools/                    # Development tools
├── Cargo.toml               # Workspace configuration
├── Cargo.lock               # Dependency lock file
├── Makefile                # Development tasks
├── docker-compose.yml      # Development environment
└── README.md               # Project overview

Development Tasks

Common Make Targets

# Build all crates
make build

# Run tests
make test

# Run integration tests
make test-integration

# Build documentation
make docs

# Serve documentation locally
make docs-serve

# Run linter
make lint

# Format code
make format

# Clean build artifacts
make clean

Custom Development Scripts

Several development scripts are available in the scripts/ directory:

# Update dependencies
./scripts/update-deps.sh

# Generate API documentation
./scripts/gen-docs.sh

# Run performance benchmarks
./scripts/benchmark.sh

# Check for unused dependencies
./scripts/check-deps.sh

Testing Strategy

Unit Tests

# Run unit tests for all crates
cargo test --lib

# Run unit tests for specific crate
cargo test -p mockforge-core

# Run with coverage
cargo tarpaulin --out Html

Integration Tests

# Run integration tests
cargo test --test integration

# Run with verbose output
cargo test --test integration -- --nocapture

End-to-End Tests

# Run E2E tests (requires Docker)
make test-e2e

# Or run manually
./scripts/test-e2e.sh

Docker Development

Development Container

# Build development container
docker build -f Dockerfile.dev -t mockforge-dev .

# Run development environment
docker run -it --rm \
  -v $(pwd):/app \
  -p 3000:3000 \
  -p 3001:3001 \
  -p 50051:50051 \
  -p 9080:9080 \
  mockforge-dev

Testing with Docker

# Run tests in container
docker run --rm -v $(pwd):/app mockforge-dev cargo test

# Build release binaries
docker run --rm -v $(pwd):/app mockforge-dev cargo build --release

Contributing Workflow

1. Choose an Issue

  • Check GitHub Issues for open tasks
  • Look for issues labeled good first issue or help wanted
  • Comment on the issue to indicate you’re working on it

2. Create a Branch

# Create feature branch
git checkout -b feature/issue-number-description

# Or create bugfix branch
git checkout -b bugfix/issue-number-description

3. Make Changes

  • Write clear, focused commits
  • Follow the code style guide
  • Add tests for new functionality
  • Update documentation as needed

4. Test Your Changes

# Run full test suite
make test

# Run integration tests
make test-integration

# Test manually if applicable
cargo run -- serve --spec examples/openapi-demo.json

5. Update Documentation

# Update user-facing docs if needed
mdbook build

# Update API docs
cargo doc

# Test documentation links
mdbook test

6. Submit a Pull Request

# Ensure branch is up to date
git fetch origin
git rebase origin/main

# Push your branch
git push origin feature/your-feature

# Create PR on GitHub with:
# - Clear title and description
# - Reference to issue number
# - Screenshots/videos for UI changes
# - Test results

Getting Help

Communication Channels

  • GitHub Issues: For bugs, features, and general discussion
  • GitHub Discussions: For questions and longer-form discussion
  • Discord: Join our community chat - For real-time chat

When to Ask for Help

  • Stuck on a technical problem for more than 2 hours
  • Unsure about design decisions
  • Need clarification on requirements
  • Found a potential security issue

Code Review Process

  • All PRs require review from at least one maintainer
  • CI must pass all checks
  • Code coverage should not decrease significantly
  • Documentation must be updated for user-facing changes

This setup guide ensures you have everything needed to contribute effectively to MockForge. Happy coding! 🚀

Code Style Guide

This guide outlines the coding standards and style guidelines for MockForge development. Consistent code style improves readability, maintainability, and collaboration.

Rust Code Style

MockForge follows the official Rust style guidelines with some project-specific conventions.

Formatting

Use rustfmt for automatic code formatting:

# Format all code
cargo fmt

# Check formatting without modifying files
cargo fmt --check

Linting

Use clippy for additional code quality checks:

# Run clippy with project settings
cargo clippy

# Run with pedantic mode for stricter checks
cargo clippy -- -W clippy::pedantic

Naming Conventions

Functions and Variables

#![allow(unused)]
fn main() {
// Good: snake_case for functions and variables
fn process_user_data(user_id: i32, data: &str) -> Result<User, Error> {
    let processed_data = validate_and_clean(data)?;
    let user_record = create_user_record(user_id, &processed_data)?;
    Ok(user_record)
}

// Bad: camelCase or PascalCase
fn processUserData(userId: i32, data: &str) -> Result<User, Error> {
    let ProcessedData = validate_and_clean(data)?;
    let userRecord = create_user_record(userId, &ProcessedData)?;
    Ok(userRecord)
}
}

Types and Traits

#![allow(unused)]
fn main() {
// Good: PascalCase for types
pub struct HttpServer {
    config: ServerConfig,
    router: Router,
}

pub trait RequestHandler {
    fn handle_request(&self, request: Request) -> Response;
}

// Bad: snake_case for types
pub struct http_server {
    config: ServerConfig,
    router: Router,
}
}

Constants

#![allow(unused)]
fn main() {
// Good: SCREAMING_SNAKE_CASE for constants
const MAX_CONNECTIONS: usize = 1000;
const DEFAULT_TIMEOUT_SECS: u64 = 30;

// Bad: camelCase or PascalCase
const maxConnections: usize = 1000;
const DefaultTimeoutSecs: u64 = 30;
}

Modules and Files

#![allow(unused)]
fn main() {
// Good: snake_case for module names
pub mod request_handler;
pub mod template_engine;

// File: request_handler.rs
// Module: request_handler
}

Documentation

Function Documentation

#![allow(unused)]
fn main() {
/// Processes a user request and returns a response.
///
/// This function handles the complete request processing pipeline:
/// 1. Validates the request data
/// 2. Applies business logic
/// 3. Returns appropriate response
///
/// # Arguments
///
/// * `user_id` - The ID of the user making the request
/// * `request_data` - The request payload as JSON
///
/// # Returns
///
/// Returns a `Result<Response, Error>` where:
/// - `Ok(response)` contains the successful response
/// - `Err(error)` contains details about what went wrong
///
/// # Errors
///
/// This function will return an error if:
/// - The user ID is invalid
/// - The request data is malformed
/// - Database operations fail
///
/// # Examples
///
/// ```rust
/// let user_id = 123;
/// let request_data = r#"{"action": "update_profile"}"#;
/// let response = process_user_request(user_id, request_data)?;
/// assert_eq!(response.status(), 200);
/// ```
pub fn process_user_request(user_id: i32, request_data: &str) -> Result<Response, Error> {
    // Implementation
}
}

Module Documentation

#![allow(unused)]
fn main() {
//! # HTTP Server Module
//!
//! This module provides HTTP server functionality for MockForge,
//! including request routing, middleware support, and response handling.
//!
//! ## Architecture
//!
//! The HTTP server uses axum as the underlying web framework and provides:
//! - OpenAPI specification integration
//! - Template-based response generation
//! - Middleware for logging and validation
//!
//! ## Example
//!
//! ```rust
//! use mockforge_http::HttpServer;
//!
//! let server = HttpServer::new(config);
//! server.serve("127.0.0.1:3000").await?;
//! ```
}

Error Handling

Custom Error Types

#![allow(unused)]
fn main() {
use thiserror::Error;

#[derive(Error, Debug)]
pub enum MockForgeError {
    #[error("Configuration error: {message}")]
    Config { message: String },

    #[error("I/O error: {source}")]
    Io {
        #[from]
        source: std::io::Error,
    },

    #[error("Template rendering error: {message}")]
    Template { message: String },

    #[error("HTTP error: {status} - {message}")]
    Http { status: u16, message: String },
}
}

Result Types

#![allow(unused)]
fn main() {
// Good: Use Result<T, MockForgeError> for fallible operations
pub fn load_config(path: &Path) -> Result<Config, MockForgeError> {
    let content = fs::read_to_string(path)
        .map_err(|e| MockForgeError::Io { source: e })?;

    let config: Config = serde_yaml::from_str(&content)
        .map_err(|e| MockForgeError::Config {
            message: format!("Failed to parse YAML: {}", e),
        })?;

    Ok(config)
}

// Bad: Using Option when you should use Result
pub fn load_config_bad(path: &Path) -> Option<Config> {
    // This loses error information
    None
}
}

Async Code

Async Function Signatures

#![allow(unused)]
fn main() {
// Good: Clear async function signatures
pub async fn process_request(request: Request) -> Result<Response, Error> {
    let data = validate_request(&request).await?;
    let result = process_data(data).await?;
    Ok(create_response(result))
}

// Bad: Unclear async boundaries
pub fn process_request(request: Request) -> impl Future<Output = Result<Response, Error>> {
    async move {
        // Implementation
    }
}
}

Tokio Usage

#![allow(unused)]
fn main() {
use tokio::sync::{Mutex, RwLock};

// Good: Use appropriate synchronization primitives
pub struct SharedState {
    data: RwLock<HashMap<String, String>>,
    counter: Mutex<i64>,
}

impl SharedState {
    pub async fn get_data(&self, key: &str) -> Option<String> {
        let data = self.data.read().await;
        data.get(key).cloned()
    }

    pub async fn increment_counter(&self) -> i64 {
        let mut counter = self.counter.lock().await;
        *counter += 1;
        *counter
    }
}
}

Testing

Unit Test Structure

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_function_basic_case() {
        // Given
        let input = "test input";
        let expected = "expected output";

        // When
        let result = process_input(input);

        // Then
        assert_eq!(result, expected);
    }

    #[test]
    fn test_function_error_case() {
        // Given
        let input = "";

        // When
        let result = process_input(input);

        // Then
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), Error::InvalidInput(_)));
    }

    #[tokio::test]
    async fn test_async_function() {
        // Given
        let client = create_test_client().await;

        // When
        let response = client.make_request().await.unwrap();

        // Then
        assert_eq!(response.status(), 200);
    }
}
}

Test Organization

#![allow(unused)]
fn main() {
// tests/integration_tests.rs
#[cfg(test)]
mod integration_tests {
    use mockforge_core::config::MockForgeConfig;

    #[tokio::test]
    async fn test_full_http_flow() {
        // Test complete request/response cycle
        let server = TestServer::new().await;
        let client = TestClient::new(server.url());

        let response = client.get("/api/users").await;
        assert_eq!(response.status(), 200);
    }
}
}

Performance Considerations

Memory Management

#![allow(unused)]
fn main() {
// Good: Use references when possible
pub fn process_data(data: &str) -> Result<String, Error> {
    // Avoid cloning unless necessary
    if data.is_empty() {
        return Err(Error::EmptyInput);
    }
    Ok(data.to_uppercase())
}

// Good: Use Cow for flexible ownership
use std::borrow::Cow;

pub fn normalize_string<'a>(input: &'a str) -> Cow<'a, str> {
    if input.chars().all(|c| c.is_lowercase()) {
        Cow::Borrowed(input)
    } else {
        Cow::Owned(input.to_lowercase())
    }
}
}

Zero-Cost Abstractions

#![allow(unused)]
fn main() {
// Good: Use iterators for memory efficiency
pub fn find_active_users(users: &[User]) -> impl Iterator<Item = &User> {
    users.iter().filter(|user| user.is_active)
}

// Bad: Collect into Vec unnecessarily
pub fn find_active_users_bad(users: &[User]) -> Vec<&User> {
    users.iter().filter(|user| user.is_active).collect()
}
}

Project-Specific Conventions

Configuration Handling

#![allow(unused)]
fn main() {
// Good: Use builder pattern for complex configuration
#[derive(Debug, Clone)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
    pub tls: Option<TlsConfig>,
}

impl Default for ServerConfig {
    fn default() -> Self {
        Self {
            host: "127.0.0.1".to_string(),
            port: 3000,
            tls: None,
        }
    }
}

impl ServerConfig {
    pub fn builder() -> ServerConfigBuilder {
        ServerConfigBuilder::default()
    }
}
}

Logging

#![allow(unused)]
fn main() {
use tracing::{info, warn, error, debug, instrument};

// Good: Use structured logging
#[instrument(skip(config))]
pub async fn start_server(config: &ServerConfig) -> Result<(), Error> {
    info!("Starting server", host = %config.host, port = config.port);

    if let Err(e) = setup_server(config).await {
        error!("Failed to start server", error = %e);
        return Err(e);
    }

    info!("Server started successfully");
    Ok(())
}
}

Feature Flags

#![allow(unused)]
fn main() {
// Good: Use feature flags for optional functionality
#[cfg(feature = "grpc")]
pub mod grpc {
    // gRPC-specific code
}

#[cfg(feature = "websocket")]
pub mod websocket {
    // WebSocket-specific code
}
}

Code Review Checklist

Before submitting code for review, ensure:

  • Code is formatted with cargo fmt
  • No clippy warnings remain
  • All tests pass
  • Documentation is updated
  • No TODO comments left in production code
  • Error messages are user-friendly
  • Performance considerations are addressed
  • Security implications are reviewed

Tools and Automation

Pre-commit Hooks

#!/bin/bash
# .git/hooks/pre-commit

# Format code
cargo fmt --check
if [ $? -ne 0 ]; then
    echo "Code is not formatted. Run 'cargo fmt' to fix."
    exit 1
fi

# Run clippy
cargo clippy -- -D warnings
if [ $? -ne 0 ]; then
    echo "Clippy found issues. Fix them before committing."
    exit 1
fi

# Run tests
cargo test
if [ $? -ne 0 ]; then
    echo "Tests are failing. Fix them before committing."
    exit 1
fi

CI Configuration

# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - uses: actions-rs/toolchain@v1
      with:
        toolchain: stable

    - name: Check formatting
      run: cargo fmt --check

    - name: Run clippy
      run: cargo clippy -- -D warnings

    - name: Run tests
      run: cargo test --verbose

    - name: Run security audit
      run: cargo audit

This style guide ensures MockForge maintains high code quality and consistency across the entire codebase. Following these guidelines makes the code more readable, maintainable, and collaborative.

Testing Guidelines

This guide outlines the testing standards and practices for MockForge contributions. Quality testing ensures code reliability, prevents regressions, and maintains system stability.

Testing Philosophy

Testing Pyramid

MockForge follows a testing pyramid approach with different types of tests serving different purposes:

End-to-End Tests (E2E)
        ↑
Integration Tests
        ↑
Unit Tests
       Base
  • Unit Tests: Test individual functions and modules in isolation
  • Integration Tests: Test component interactions and data flow
  • End-to-End Tests: Test complete user workflows and system behavior

Testing Principles

  1. Test First: Write tests before implementation when possible
  2. Test Behavior: Test what the code does, not how it does it
  3. Test Boundaries: Focus on edge cases and error conditions
  4. Keep Tests Fast: Tests should run quickly to encourage frequent execution
  5. Make Tests Reliable: Tests should be deterministic and not flaky

Unit Testing Requirements

Test Coverage

All new code must include unit tests with the following minimum coverage:

  • Functions: Test all public functions with valid inputs
  • Error Cases: Test all error conditions and edge cases
  • Branches: Test all conditional branches (if/else, match arms)
  • Loops: Test loop boundaries (empty, single item, multiple items)

Test Structure

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_function_name_description() {
        // Given: Set up test data and preconditions
        let input = create_test_input();
        let expected = create_expected_output();

        // When: Execute the function under test
        let result = function_under_test(input);

        // Then: Verify the result matches expectations
        assert_eq!(result, expected);
    }

    #[test]
    fn test_function_name_error_case() {
        // Given: Set up error condition
        let invalid_input = create_invalid_input();

        // When: Execute the function
        let result = function_under_test(invalid_input);

        // Then: Verify error handling
        assert!(result.is_err());
        let error = result.unwrap_err();
        assert!(matches!(error, ExpectedError::Variant));
    }
}
}

Test Naming Conventions

#![allow(unused)]
fn main() {
// Good: Descriptive test names
#[test]
fn test_parse_openapi_spec_validates_required_fields() { ... }
#[test]
fn test_template_engine_handles_missing_variables() { ... }
#[test]
fn test_http_server_rejects_invalid_content_type() { ... }

// Bad: Non-descriptive names
#[test]
fn test_function() { ... }
#[test]
fn test_case_1() { ... }
#[test]
fn test_error() { ... }
}

Test Data Management

Test Fixtures

#![allow(unused)]
fn main() {
// Use shared test fixtures for common data
pub fn sample_openapi_spec() -> &'static str {
    r#"
    openapi: 3.0.3
    info:
      title: Test API
      version: 1.0.0
    paths:
      /users:
        get:
          responses:
            '200':
              description: Success
    "#
}

pub fn sample_user_data() -> User {
    User {
        id: "123".to_string(),
        name: "John Doe".to_string(),
        email: "[email protected]".to_string(),
    }
}
}

Test Utilities

#![allow(unused)]
fn main() {
// Create test utilities for common setup
pub struct TestServer {
    server_handle: Option<JoinHandle<()>>,
    base_url: String,
}

impl TestServer {
    pub async fn new() -> Self {
        // Start test server
        // Return configured instance
    }

    pub fn url(&self) -> &str {
        &self.base_url
    }
}

impl Drop for TestServer {
    fn drop(&mut self) {
        // Clean up server
    }
}
}

Integration Testing Standards

When to Write Integration Tests

Integration tests are required for:

  • API Boundaries: HTTP endpoints, gRPC services, WebSocket connections
  • Database Operations: Data persistence and retrieval
  • External Services: Third-party API integrations
  • File I/O: Configuration loading, fixture management
  • Component Communication: Cross-crate interactions

Integration Test Structure

#![allow(unused)]
fn main() {
#[cfg(test)]
mod integration_tests {
    use mockforge_core::config::MockForgeConfig;

    #[tokio::test]
    async fn test_http_server_startup() {
        // Given: Configure test server
        let config = create_test_config();
        let server = HttpServer::new(config);

        // When: Start the server
        let addr = server.local_addr();
        tokio::spawn(async move {
            server.serve().await.unwrap();
        });

        // Wait for startup
        tokio::time::sleep(Duration::from_millis(100)).await;

        // Then: Verify server is responding
        let client = reqwest::Client::new();
        let response = client
            .get(format!("http://{}/health", addr))
            .send()
            .await
            .unwrap();

        assert_eq!(response.status(), 200);
    }
}
}

Database Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod database_tests {
    use sqlx::PgPool;

    #[sqlx::test]
    async fn test_user_creation(pool: PgPool) {
        // Given: Clean database state
        sqlx::query!("DELETE FROM users").execute(&pool).await.unwrap();

        // When: Create a user
        let user_id = create_user(&pool, "[email protected]").await.unwrap();

        // Then: Verify user exists
        let user = sqlx::query!("SELECT * FROM users WHERE id = $1", user_id)
            .fetch_one(&pool)
            .await
            .unwrap();

        assert_eq!(user.email, "[email protected]");
    }
}
}

End-to-End Testing Requirements

E2E Test Scenarios

E2E tests must cover:

  • Happy Path: Complete successful user workflows
  • Error Recovery: System behavior under failure conditions
  • Data Persistence: State changes across operations
  • Performance: Response times and resource usage
  • Security: Authentication and authorization flows

E2E Test Implementation

#![allow(unused)]
fn main() {
#[cfg(test)]
mod e2e_tests {
    use std::process::Command;
    use std::time::Duration;

    #[test]
    fn test_complete_api_workflow() {
        // Start MockForge server
        let mut server = Command::new("cargo")
            .args(&["run", "--release", "--", "serve", "--spec", "test-api.yaml"])
            .spawn()
            .unwrap();

        // Wait for server startup
        std::thread::sleep(Duration::from_secs(3));

        // Execute complete workflow
        let result = run_workflow_test();
        assert!(result.is_ok());

        // Cleanup
        server.kill().unwrap();
    }
}
}

Test Quality Standards

Code Coverage Requirements

  • Minimum Coverage: 80% overall, 90% for critical paths
  • Branch Coverage: All conditional branches must be tested
  • Error Path Coverage: All error conditions must be tested

Performance Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod performance_tests {
    use criterion::Criterion;

    fn benchmark_template_rendering(c: &mut Criterion) {
        let engine = TemplateEngine::new();

        c.bench_function("render_simple_template", |b| {
            b.iter(|| {
                engine.render("Hello {{name}}", &[("name", "World")]);
            })
        });
    }
}
}

Load Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod load_tests {
    use tokio::time::{Duration, Instant};

    #[tokio::test]
    async fn test_concurrent_requests() {
        let client = reqwest::Client::new();
        let start = Instant::now();

        // Spawn 100 concurrent requests
        let handles: Vec<_> = (0..100).map(|_| {
            let client = client.clone();
            tokio::spawn(async move {
                client.get("http://localhost:3000/api/users")
                    .send()
                    .await
                    .unwrap()
            })
        }).collect();

        // Wait for all requests to complete
        for handle in handles {
            let response = handle.await.unwrap();
            assert_eq!(response.status(), 200);
        }

        let duration = start.elapsed();
        assert!(duration < Duration::from_secs(5), "Load test took too long: {:?}", duration);
    }
}
}

Testing Tools and Frameworks

Required Testing Dependencies

[dev-dependencies]
tokio-test = "0.4"
proptest = "1.0"          # Property-based testing
criterion = "0.4"         # Benchmarking
assert_cmd = "2.0"        # CLI testing
predicates = "2.1"        # Value assertions
tempfile = "3.0"          # Temporary files

Mocking and Stubbing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod mock_tests {
    use mockall::mock;

    #[mockall::mock]
    trait Database {
        async fn get_user(&self, id: i32) -> Result<User, Error>;
        async fn save_user(&self, user: User) -> Result<(), Error>;
    }

    #[tokio::test]
    async fn test_service_with_mocks() {
        let mut mock_db = MockDatabase::new();

        mock_db
            .expect_get_user()
            .with(eq(123))
            .returning(|_| Ok(User { id: 123, name: "Test".to_string() }));

        let service = UserService::new(mock_db);
        let user = service.get_user(123).await.unwrap();

        assert_eq!(user.name, "Test");
    }
}
}

Property-Based Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod property_tests {
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn test_template_rendering_with_random_input(
            input in "\\PC*",  // Any printable character except control chars
            name in "[a-zA-Z]{1,10}"
        ) {
            let engine = TemplateEngine::new();
            let context = &[("name", &name)];

            // Should not panic regardless of input
            let _result = engine.render(&input, context);
        }
    }
}
}

Test Organization and Naming

File Structure

src/
├── lib.rs
├── module.rs
└── module/
    ├── mod.rs
    └── submodule.rs

tests/
├── unit/
│   ├── module_tests.rs
│   └── submodule_tests.rs
├── integration/
│   ├── api_tests.rs
│   └── database_tests.rs
└── e2e/
    ├── workflow_tests.rs
    └── performance_tests.rs

Test Module Organization

#![allow(unused)]
fn main() {
// tests/unit/template_tests.rs
#[cfg(test)]
mod template_tests {
    use mockforge_core::templating::TemplateEngine;

    // Unit tests for template functionality
}

// tests/integration/http_tests.rs
#[cfg(test)]
mod http_integration_tests {
    use mockforge_http::HttpServer;

    // Integration tests for HTTP server
}

// tests/e2e/api_workflow_tests.rs
#[cfg(test)]
mod e2e_tests {
    // End-to-end workflow tests
}
}

CI/CD Integration

GitHub Actions Testing

name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - uses: dtolnay/rust-toolchain@stable

    - name: Cache dependencies
      uses: Swatinem/rust-cache@v2

    - name: Check formatting
      run: cargo fmt --check

    - name: Run clippy
      run: cargo clippy -- -D warnings

    - name: Run tests
      run: cargo test --verbose

    - name: Run integration tests
      run: cargo test --test integration

    - name: Generate coverage
      run: |
        cargo install cargo-tarpaulin
        cargo tarpaulin --out Xml --output-dir coverage

    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        file: coverage/cobertura.xml

Test Result Reporting

- name: Run tests with JUnit output
  run: |
    cargo install cargo2junit
    cargo test -- -Z unstable-options --format json | cargo2junit > test-results.xml

- name: Publish test results
  uses: EnricoMi/publish-unit-test-result-action@v2
  with:
    files: test-results.xml

Best Practices

Test Isolation

#![allow(unused)]
fn main() {
#[cfg(test)]
mod isolated_tests {
    use tempfile::TempDir;

    #[test]
    fn test_file_operations() {
        // Use temporary directory for isolation
        let temp_dir = TempDir::new().unwrap();
        let file_path = temp_dir.path().join("test.txt");

        // Test file operations
        write_test_file(&file_path);
        assert!(file_path.exists());

        // Cleanup happens automatically
    }
}
}

Test Data Management

#![allow(unused)]
fn main() {
#[cfg(test)]
mod test_data {
    use once_cell::sync::Lazy;

    static TEST_USERS: Lazy<Vec<User>> = Lazy::new(|| {
        vec![
            User { id: 1, name: "Alice".to_string() },
            User { id: 2, name: "Bob".to_string() },
        ]
    });

    #[test]
    fn test_user_operations() {
        let users = TEST_USERS.clone();
        // Use shared test data
    }
}
}

Asynchronous Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod async_tests {
    use tokio::time::{timeout, Duration};

    #[tokio::test]
    async fn test_async_operation_with_timeout() {
        let result = timeout(Duration::from_secs(5), async_operation()).await;

        match result {
            Ok(Ok(data)) => assert!(data.is_valid()),
            Ok(Err(e)) => panic!("Operation failed: {}", e),
            Err(_) => panic!("Operation timed out"),
        }
    }

    #[tokio::test]
    async fn test_concurrent_operations() {
        let (result1, result2) = tokio::join(
            operation1(),
            operation2()
        );

        assert!(result1.is_ok());
        assert!(result2.is_ok());
    }
}
}

Test Flakiness Prevention

#![allow(unused)]
fn main() {
#[cfg(test)]
mod reliable_tests {
    #[test]
    fn test_with_retries() {
        let mut attempts = 0;
        let max_attempts = 3;

        loop {
            attempts += 1;

            match potentially_flaky_operation() {
                Ok(result) => {
                    assert!(result.is_valid());
                    break;
                }
                Err(e) if attempts < max_attempts => {
                    eprintln!("Attempt {} failed: {}, retrying...", attempts, e);
                    std::thread::sleep(Duration::from_millis(100));
                    continue;
                }
                Err(e) => panic!("Operation failed after {} attempts: {}", max_attempts, e),
            }
        }
    }
}
}

Security Testing

Input Validation Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod security_tests {
    #[test]
    fn test_sql_injection_prevention() {
        let malicious_input = "'; DROP TABLE users; --";
        let result = sanitize_sql_input(malicious_input);

        assert!(!result.contains("DROP"));
        assert!(!result.contains(";"));
    }

    #[test]
    fn test_xss_prevention() {
        let malicious_input = "<script>alert('xss')</script>";
        let result = sanitize_html_input(malicious_input);

        assert!(!result.contains("<script>"));
        assert!(result.contains("&lt;script&gt;"));
    }

    #[test]
    fn test_path_traversal_prevention() {
        let malicious_input = "../../../etc/passwd";
        let result = validate_file_path(malicious_input);

        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), ValidationError::PathTraversal));
    }
}
}

Authentication Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod auth_tests {
    #[tokio::test]
    async fn test_unauthorized_access() {
        let client = create_test_client();

        let response = client
            .get("/admin/users")
            .send()
            .await
            .unwrap();

        assert_eq!(response.status(), 401);
    }

    #[tokio::test]
    async fn test_authorized_access() {
        let client = create_authenticated_client();

        let response = client
            .get("/admin/users")
            .send()
            .await
            .unwrap();

        assert_eq!(response.status(), 200);
    }
}
}

This comprehensive testing guide ensures MockForge maintains high quality and reliability through thorough automated testing at all levels.

Release Process

This guide outlines the complete process for releasing new versions of MockForge, from planning through deployment and post-release activities.

Release Planning

Version Numbering

MockForge follows Semantic Versioning (SemVer):

MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]

Examples:
- 1.0.0 (stable release)
- 1.1.0 (minor release with new features)
- 1.1.1 (patch release with bug fixes)
- 2.0.0-alpha.1 (pre-release)
- 1.0.0+20230912 (build metadata)

When to Increment

  • MAJOR (X.0.0): Breaking changes to public API
  • MINOR (X.Y.0): New features, backward compatible
  • PATCH (X.Y.Z): Bug fixes, backward compatible

Release Types

Major Releases

  • Breaking API changes
  • Major feature additions
  • Architectural changes
  • Extended testing period (2-4 weeks beta)

Minor Releases

  • New features and enhancements
  • Backward compatible API changes
  • Standard testing period (1-2 weeks)

Patch Releases

  • Critical bug fixes
  • Security patches
  • Documentation updates
  • Minimal testing period (3-5 days)

Pre-releases

  • Alpha/Beta/RC versions
  • Feature previews
  • Breaking change previews
  • Limited distribution

Pre-Release Checklist

1. Code Quality Verification

# Run complete test suite
make test

# Run integration tests
make test-integration

# Run E2E tests
make test-e2e

# Check code quality
make lint
make format-check

# Security audit
cargo audit

# Check for unused dependencies
cargo +nightly udeps

# Performance benchmarks
make benchmark

2. Documentation Updates

# Update CHANGELOG.md with release notes
# IMPORTANT: Tag all changelog entries with pillars: [Reality], [Contracts], [DevX], [Cloud], [AI]
# See docs/PILLARS.md for pillar definitions and examples
# Update version numbers in documentation
# Build and test documentation
make docs
make docs-serve

# Test documentation links
mdbook test

Changelog Pillar Tagging Requirements:

All changelog entries must be tagged with at least one pillar. The release scripts will validate this automatically.

Format:

- **[Reality] Feature description**

- **[Contracts][DevX] Multi-pillar feature**

Pillars:

  • [Reality] – Everything that makes mocks feel like a real, evolving backend
  • [Contracts] – Schema, drift, validation, and safety nets
  • [DevX] – SDKs, generators, playgrounds, ergonomics
  • [Cloud] – Registry, orgs, governance, monetization, marketplace
  • [AI] – LLM/voice flows, AI diff/assist, generative behaviors

See docs/PILLARS.md for detailed pillar definitions, feature mappings, and examples.

3. Version Bump

# Update version in Cargo.toml files
# Update version in package metadata
# Update version in documentation

# Example version bump script
#!/bin/bash
NEW_VERSION=$1

# Update workspace Cargo.toml
sed -i "s/^version = .*/version = \"$NEW_VERSION\"/" Cargo.toml

# Update all crate Cargo.toml files
find crates -name "Cargo.toml" -exec sed -i "s/^version = .*/version = \"$NEW_VERSION\"/" {} \;

# Update README and documentation version references
sed -i "s/mockforge [0-9]\+\.[0-9]\+\.[0-9]\+/mockforge $NEW_VERSION/g" README.md

4. Branch Management

# Create release branch
git checkout -b release/v$NEW_VERSION

# Cherry-pick approved commits
# Or merge from develop/main

# Tag the release
git tag -a v$NEW_VERSION -m "Release version $NEW_VERSION"

# Push branch and tag
git push origin release/v$NEW_VERSION
git push origin v$NEW_VERSION

Release Build Process

1. Build Verification

# Clean build
cargo clean

# Build all targets
cargo build --release --all-targets

# Build specific platforms if needed
cargo build --release --target x86_64-unknown-linux-gnu
cargo build --release --target x86_64-apple-darwin
cargo build --release --target x86_64-pc-windows-msvc

# Test release build
./target/release/mockforge-cli --version

2. Binary Distribution

Linux/macOS Packages

# Strip debug symbols
strip target/release/mockforge-cli

# Create distribution archives
VERSION=1.0.0
tar -czf mockforge-v${VERSION}-x86_64-linux.tar.gz \
  -C target/release mockforge-cli

tar -czf mockforge-v${VERSION}-x86_64-macos.tar.gz \
  -C target/release mockforge-cli

Debian Packages

# Install cargo-deb
cargo install cargo-deb

# Build .deb package
cargo deb

# Test package installation
sudo dpkg -i target/debian/mockforge_*.deb

Docker Images

# Dockerfile.release
FROM rust:1.70-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/mockforge-cli /usr/local/bin/mockforge-cli
EXPOSE 3000 3001 50051 9080
CMD ["mockforge-cli", "serve"]
# Build and push Docker image
docker build -f Dockerfile.release -t mockforge:$VERSION .
docker tag mockforge:$VERSION mockforge:latest
docker push mockforge:$VERSION
docker push mockforge:latest

3. Cross-Platform Builds

# Use cross for cross-compilation
cargo install cross

# Build for different architectures
cross build --release --target aarch64-unknown-linux-gnu
cross build --release --target x86_64-unknown-linux-musl

# Create release archives for each platform
for target in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu x86_64-apple-darwin x86_64-pc-windows-msvc; do
  cross build --release --target $target
  if [[ $target == *"windows"* ]]; then
    zip -j mockforge-$VERSION-$target.zip target/$target/release/mockforge-cli.exe
  else
    tar -czf mockforge-$VERSION-$target.tar.gz -C target/$target/release mockforge-cli
  fi
done

Release Deployment

1. GitHub Release

# Create GitHub release (manual or automated)
gh release create v$VERSION \
  --title "MockForge v$VERSION" \
  --notes-file release-notes.md \
  --draft

# Upload release assets
gh release upload v$VERSION \
  mockforge-v$VERSION-x86_64-linux.tar.gz \
  mockforge-v$VERSION-x86_64-macos.tar.gz \
  mockforge-v$VERSION-x86_64-windows.zip \
  mockforge_$VERSION_amd64.deb

# Publish release
gh release edit v$VERSION --draft=false

2. Package Registries

Crates.io Publication

# Publish all crates to crates.io
# Note: Must be done in dependency order

# Publish core first
cd crates/mockforge-core
cargo publish

# Then other crates
cd ../mockforge-http
cargo publish

cd ../mockforge-ws
cargo publish

cd ../mockforge-grpc
cargo publish

cd ../mockforge-data
cargo publish

cd ../mockforge-ui
cargo publish

# Finally CLI
cd ../mockforge-cli
cargo publish

Docker Hub

Note: Docker Hub publishing is planned for future releases. The organization and repository need to be set up first.

Once Docker Hub is configured, use these commands:

# Build the Docker image with version tag
docker build -t saasy-solutions/mockforge:$VERSION .
docker tag saasy-solutions/mockforge:$VERSION saasy-solutions/mockforge:latest

# Push to Docker Hub (requires authentication)
docker login
docker push saasy-solutions/mockforge:$VERSION
docker push saasy-solutions/mockforge:latest

For now, users should build the Docker image locally as documented in the Installation Guide.

3. Homebrew (macOS)

# Formula/mockforge.rb
class Mockforge < Formula
  desc "Advanced API Mocking Platform"
  homepage "https://github.com/SaaSy-Solutions/mockforge"
  url "https://github.com/SaaSy-Solutions/mockforge/releases/download/v#{version}/mockforge-v#{version}-x86_64-macos.tar.gz"
  sha256 "..."

  def install
    bin.install "mockforge-cli"
  end

  test do
    system "#{bin}/mockforge-cli", "--version"
  end
end

4. Package Managers

APT Repository (Ubuntu/Debian)

# Set up PPA or repository
# Upload .deb packages
# Update package indices

Snapcraft

# snapcraft.yaml
name: mockforge
version: '1.0.0'
summary: Advanced API Mocking Platform
description: |
  MockForge is a comprehensive API mocking platform supporting HTTP, WebSocket, and gRPC protocols.

grade: stable
confinement: strict

apps:
  mockforge:
    command: mockforge-cli
    plugs: [network, network-bind]

parts:
  mockforge:
    plugin: rust
    source: .
    build-packages: [pkg-config, libssl-dev]

Post-Release Activities

1. Announcement

GitHub Release Notes

## What's New in MockForge v1.0.0

### 🚀 Major Features
- Multi-protocol support (HTTP, WebSocket, gRPC)
- Advanced templating system
- Web-based admin UI
- Comprehensive testing framework

### 🐛 Bug Fixes
- Fixed template rendering performance
- Resolved WebSocket connection stability
- Improved error messages

### 📚 Documentation
- Complete API reference
- Getting started guides
- Troubleshooting documentation

### 🤝 Contributors
Special thanks to all contributors!

### 🔗 Links
- [Documentation](https://docs.mockforge.dev)
- [GitHub Repository](https://github.com/SaaSy-Solutions/mockforge)
- [Issue Tracker](https://github.com/SaaSy-Solutions/mockforge/issues)

Social Media & Community

# Post to social media
# Update Discord/Slack channels
# Send email newsletter
# Update website/blog

2. Monitoring & Support

Release Health Checks

# Monitor installation success
# Check for immediate bug reports
# Monitor CI/CD pipelines
# Track adoption metrics

# Example monitoring script
#!/bin/bash
VERSION=$1

# Check GitHub release downloads
gh release view v$VERSION --json assets -q '.assets[].downloadCount'

# Check crates.io download stats
curl -s "https://crates.io/api/v1/crates/mockforge-cli/downloads" | jq '.versions[0].downloads'

# Monitor error reports
gh issue list --label bug --state open --limit 10

Support Channels

  • GitHub Issues: Bug reports and feature requests
  • GitHub Discussions: General questions and support
  • Discord: Join our community chat - Real-time community support
  • Documentation: Self-service troubleshooting

3. Follow-up Releases

Hotfix Process

For critical issues discovered post-release:

# Create hotfix branch from release tag
git checkout -b hotfix/critical-bug-fix v1.0.0

# Apply fix
# Write test
# Update CHANGELOG

# Create patch release
NEW_VERSION=1.0.1
git tag -a v$NEW_VERSION
git push origin v$NEW_VERSION

# Deploy hotfix

4. Analytics & Metrics

Release Metrics

  • Download counts across platforms
  • Installation success rates
  • User adoption and usage patterns
  • Performance benchmarks vs previous versions
  • Community feedback and sentiment

Continuous Improvement

# Post-release retrospective template
## Release Summary
- Version: v1.0.0
- Release Date: YYYY-MM-DD
- Duration: X weeks

## What Went Well
- [ ] Smooth release process
- [ ] No critical bugs found
- [ ] Good community reception

## Areas for Improvement
- [ ] Documentation could be clearer
- [ ] Testing took longer than expected
- [ ] More platform support needed

## Action Items
- [ ] Improve release documentation
- [ ] Automate more of the process
- [ ] Add more platform builds

Release Automation

GitHub Actions Release Workflow

# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set version
      run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV

    - name: Build release binaries
      run: |
        cargo build --release
        strip target/release/mockforge-cli

    - name: Create release archives
      run: |
        tar -czf mockforge-${VERSION}-linux-x64.tar.gz -C target/release mockforge-cli
        zip mockforge-${VERSION}-linux-x64.zip target/release/mockforge-cli

    - name: Create GitHub release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: MockForge ${{ env.VERSION }}
        body: |
          ## What's New

          See [CHANGELOG.md](CHANGELOG.md) for details.

          ## Downloads

          - Linux x64: [mockforge-${{ env.VERSION }}-linux-x64.tar.gz](mockforge-${{ env.VERSION }}-linux-x64.tar.gz)
        draft: false
        prerelease: false

    - name: Upload release assets
      uses: actions/upload-release-asset@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        upload_url: ${{ steps.create_release.outputs.upload_url }}
        asset_path: ./mockforge-${{ env.VERSION }}-linux-x64.tar.gz
        asset_name: mockforge-${{ env.VERSION }}-linux-x64.tar.gz
        asset_content_type: application/gzip

Automated Publishing

# Publish to crates.io on release
- name: Publish to crates.io
  run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}
  if: startsWith(github.ref, 'refs/tags/')

# Build and push Docker image
- name: Build and push Docker image
  uses: docker/build-push-action@v3
  with:
    context: .
    push: true
    tags: mockforge/mockforge:${{ env.VERSION }},mockforge/mockforge:latest

Emergency Releases

Security Vulnerabilities

For security issues requiring immediate release:

  1. Assess Severity: Determine CVSS score and impact
  2. Develop Fix: Create minimal fix with comprehensive tests
  3. Bypass Normal Process: Skip extended testing for critical security fixes
  4. Accelerated Release: 24-48 hour release cycle
  5. Public Disclosure: Coordinate with security community

Critical Bug Fixes

For show-stopping bugs affecting production:

  1. Immediate Assessment: Evaluate user impact and severity
  2. Rapid Development: 1-2 day fix development
  3. Limited Testing: Focus on regression and critical path tests
  4. Fast-Track Release: 3-5 day release cycle

This comprehensive release process ensures MockForge releases are reliable, well-tested, and properly distributed across all supported platforms and package managers.

The Five Pillars of MockForge

Version: 1.0.0 Last Updated: 2025-01-27

MockForge is built on five foundational pillars that define our product vision and guide every feature we build. These pillars ensure that MockForge delivers a cohesive, powerful mocking experience that scales from solo developers to enterprise teams.

Overview

Every feature in MockForge maps to one or more pillars. This structure helps us:

  • Communicate value clearly in changelogs, docs, and marketing
  • Prioritize development based on pillar investment
  • Maintain consistency across features and releases
  • Guide users to the right features for their needs

The Five Pillars

[Reality] – Everything that makes mocks feel like a real, evolving backend

Purpose: Make mocks indistinguishable from production backends through realistic behavior, state management, and dynamic data generation.

Key Capabilities:

  • Realistic data generation with relationships and constraints
  • Stateful behavior and persistence
  • Network condition simulation (latency, packet loss, failures)
  • Time-based mutations and temporal simulation
  • Progressive data evolution and drift
  • Multi-protocol support (HTTP, gRPC, WebSocket, Kafka, MQTT, AMQP, SMTP, FTP, TCP)

Example Features:

  • Reality Continuum: Blend mock and real data with configurable reality levels
  • Reality Slider: Hot-reload reality level adjustments
  • Smart Personas: Consistent cross-endpoint data generation
  • Generative Schema Mode: Dynamic mock data generation without seed data
  • Chaos Lab: Interactive network condition simulation
  • Deceptive Deploy: Advanced testing scenarios with realistic failures
  • Virtual Backend Reality (VBR): Virtual database layer with CRUD operations
  • Temporal Simulation: Time travel and time-based data mutations
  • Latency Injection: Configurable latency profiles and recording
  • Response Selection Modes: Sequential, random, and weighted response selection
  • Template Expansion: Dynamic data generation with faker functions
  • Capture Scrubbing: Deterministic replay with data sanitization

Use Cases:

  • Frontend teams need realistic data that evolves over time
  • Testing resilience and failure scenarios
  • Simulating production-like network conditions
  • Creating believable mock backends before real APIs exist

[Contracts] – Schema, drift, validation, and safety nets

Purpose: Ensure API contracts are correct, validated, and stay in sync with real backends.

Key Capabilities:

  • OpenAPI/GraphQL schema validation
  • Request/response validation with detailed error reporting
  • Contract drift detection and monitoring
  • Automatic API sync and change detection
  • Schema-driven mock generation
  • Cross-endpoint validation and referential integrity
  • Multi-protocol contract support (HTTP, gRPC, WebSocket, MQTT, Kafka)
  • Contract fitness functions for quality enforcement
  • Consumer impact analysis for downstream dependencies

Example Features:

  • AI Contract Diff: Compare and visualize API contract changes
  • Automatic API Sync & Change Detection: Periodic polling and sync for upstream API changes
  • Request/Response Validation: Built-in validation with configurable modes (disabled, warn, enforce)
  • OpenAPI Integration: Full OpenAPI v3 support with deep $ref resolution
  • Schema Validation: Composite schemas (oneOf/anyOf/allOf) support
  • Validation Modes: Runtime admin UI to view/toggle validation mode
  • Contract Testing: Verify API contracts match specifications
  • Protocol Contracts: gRPC, WebSocket, MQTT, and Kafka contract management
  • Fitness Functions: Custom tests to enforce contract quality and evolution rules
  • Consumer Impact Analysis: Map endpoints to SDK methods and consuming applications
  • Drift Budgets: Configurable thresholds for acceptable contract changes

Use Cases:

  • Catch breaking changes before they reach production
  • Ensure mocks stay in sync with real APIs
  • Validate API contracts during development
  • Detect schema drift automatically

[DevX] – SDKs, generators, playgrounds, ergonomics

Purpose: Make MockForge effortless to use, integrate, and extend for developers.

Key Capabilities:

  • Multi-language SDKs (Rust, Node.js, Python, Go, Java, .NET)
  • Client code generation (React, Vue, Angular, Svelte)
  • Interactive playgrounds and admin UI
  • CLI tooling and configuration management
  • Comprehensive documentation and examples
  • Plugin system for extensibility

Example Features:

  • ForgeConnect SDK: Complete SDK implementation with full feature set
  • GraphQL + REST Playground: Interactive playground with workspace filtering
  • Multi-Language SDKs: Native SDKs for 6 languages
  • Client Generators: React, Vue, Angular, Svelte client code generation
  • CLI Tool: Full-featured command-line interface
  • Admin UI: Modern React-based admin interface
  • Configuration Management: YAML/JSON config files with profiles
  • Browser Proxy Mode: Seamless integration with browser workflows
  • Git Sync: Workspace synchronization via Git
  • Plugin System: WASM-based plugin architecture
  • E2E Test Suite: Comprehensive end-to-end testing tools
  • Custom Routes: Flexible routing configuration
  • Voice + LLM Interface: Voice interface with Speech-to-Text support
  • WireMock-Inspired Features: Familiar patterns for WireMock users

Use Cases:

  • Embed mock servers directly in test suites
  • Generate type-safe API clients automatically
  • Integrate with existing development workflows
  • Extend functionality with custom plugins

[Cloud] – Registry, orgs, governance, monetization, marketplace

Purpose: Enable team collaboration, sharing, and scaling from solo developers to enterprise organizations.

Key Capabilities:

  • Organization and user management
  • Scenario marketplace and sharing
  • Registry server for mock distribution
  • Cloud workspaces and synchronization
  • Governance and access controls
  • Monetization infrastructure

Example Features:

  • Cloud Workspaces: Shared workspaces with team collaboration
  • Scenario Marketplace: Browse and share mock scenarios
  • Registry Server: Centralized mock distribution and discovery
  • Organization Management: Multi-tenant organization support
  • User Management: Team member and permission management
  • Cloud Sync: Synchronize workspaces across devices
  • Security Controls: Enterprise-grade access controls and audit trails
  • Cloud Monetization: Pricing models and subscription management
  • Enhanced Metrics: Team-level analytics and monitoring

Use Cases:

  • Share mock scenarios across teams
  • Manage enterprise deployments
  • Discover and reuse community scenarios
  • Scale from individual to team usage

[AI] – LLM/voice flows, AI diff/assist, generative behaviors

Purpose: Leverage artificial intelligence to automate mock generation, enhance data realism, and assist developers.

Key Capabilities:

  • LLM-powered mock generation
  • AI-driven data synthesis
  • Voice interface for mock creation
  • Intelligent contract analysis
  • Generative data behaviors
  • Natural language to mock conversion

Example Features:

  • MockAI: Intelligent mock generation from natural language
  • AI Response Generation: LLM-powered realistic response generation
  • AI Contract Diff: AI-assisted contract comparison and analysis
  • Voice + LLM Interface: Voice-driven mock creation and management
  • Generative Schema Mode: AI-powered schema extrapolation
  • AI Event Streams: LLM-generated narrative-driven WebSocket events
  • Data Drift Simulation: AI-driven evolving mock data
  • Smart Data Generation: RAG-powered synthetic data with relationship awareness

Use Cases:

  • Generate mocks from natural language descriptions
  • Create realistic data without manual configuration
  • Analyze and compare API contracts intelligently
  • Build mocks through voice commands

Pillar Feature Matrix

This matrix shows how key MockForge features map to the five pillars:

FeatureRealityContractsDevXCloudAI
Reality Continuum✅
Reality Slider✅✅
Smart Personas✅✅
Generative Schema Mode✅✅✅
Chaos Lab✅✅
Deceptive Deploy✅
VBR Engine✅✅
Temporal Simulation✅✅
AI Contract Diff✅✅✅
Automatic API Sync✅
Request/Response Validation✅✅
ForgeConnect SDK✅
Client Generators✅✅
GraphQL + REST Playground✅
Admin UI✅
Plugin System✅
Cloud Workspaces✅
Scenario Marketplace✅
Registry Server✅
Organization Management✅
MockAI✅✅
Voice + LLM Interface✅✅
AI Event Streams✅✅
Data Drift Simulation✅✅

Using Pillars in Changelog Entries

When adding features to the changelog, tag them with one or more relevant pillars:

- **[Reality] Smart Personas** with array generation and relationship inference

- **[Contracts][DevX] AI Contract Diff** with interactive playground integration

- **[Cloud] Organization management endpoints** for team collaboration

Guidelines:

  • Use [Pillar] format with square brackets
  • Multiple pillars: [Pillar1][Pillar2]
  • Tag the primary pillar first, then secondary pillars
  • Every major feature should have at least one pillar tag
  • Minor fixes and internal changes may not need tags

Pillar Investment by Release

Understanding which pillars receive investment in each release helps users understand the product direction:

  • Reality-heavy releases: Focus on making mocks more realistic and production-like
  • Contracts-heavy releases: Emphasis on validation, sync, and contract safety
  • DevX-heavy releases: Improved ergonomics, SDKs, and developer experience
  • Cloud-heavy releases: Team features, collaboration, and enterprise capabilities
  • AI-heavy releases: Intelligent automation and AI-powered features

Documentation by Pillar

This section organizes MockForge documentation by pillar to help you find relevant guides quickly.

New to MockForge? Start with Journeys by Pillar to choose the onboarding path that best fits your needs.

[Reality] Documentation

Getting Started:

Core Features:

Advanced:

[Contracts] Documentation

Getting Started:

Core Features:

Advanced:

[DevX] Documentation

Getting Started:

Core Features:

Advanced:

[Cloud] Documentation

Getting Started:

Core Features:

Advanced:

[AI] Documentation

Getting Started:

Core Features:

Advanced:

Cross-Pillar Documentation


References


Questions?

If you’re unsure which pillar(s) a feature belongs to:

  1. Reality: Does it make mocks feel more like real backends?
  2. Contracts: Does it validate, sync, or monitor API contracts?
  3. DevX: Does it improve developer experience or ergonomics?
  4. Cloud: Does it enable team collaboration or sharing?
  5. AI: Does it use AI/LLM to automate or enhance functionality?

Many features span multiple pillars—that’s intentional and encouraged!

Configuration Schema

MockForge supports comprehensive configuration through YAML files. This schema reference documents all available configuration options, their types, defaults, and usage examples.

Complete Configuration Template

For a fully annotated configuration template with all options documented inline, see:

config.template.yaml

This template includes:

  • Every configuration field with inline documentation
  • Default values and valid ranges
  • Example configurations for common scenarios
  • Comments explaining each option’s purpose

Quick Start

# Initialize a new configuration
mockforge init my-project

# Validate your configuration
mockforge config validate

# Start with validated config
mockforge serve --config mockforge.yaml

See the Configuration Validation Guide for validation best practices.

File Format

Configuration files use YAML format with the following structure:

# Top-level configuration sections
server:        # Server port and binding configuration
admin:         # Admin UI settings
validation:    # Request validation settings
response:      # Response processing options
chaos:         # Chaos engineering features
grpc:          # gRPC-specific settings
websocket:     # WebSocket-specific settings
logging:       # Logging configuration

Server Configuration

server.http_port (integer, default: 3000)

HTTP server port for REST API endpoints.

server:
  http_port: 9080

server.ws_port (integer, default: 3001)

WebSocket server port for real-time connections.

server:
  ws_port: 8081

server.grpc_port (integer, default: 50051)

gRPC server port for protocol buffer services.

server:
  grpc_port: 9090

server.bind (string, default: “0.0.0.0”)

Network interface to bind servers to.

server:
  bind: "127.0.0.1"  # Bind to localhost only

Admin UI Configuration

admin.enabled (boolean, default: false)

Enable the web-based admin interface.

admin:
  enabled: true

admin.port (integer, default: 9080)

Port for the admin UI server.

admin:
  port: 9090

admin.embedded (boolean, default: false)

Embed admin UI under the main HTTP server instead of running standalone.

admin:
  embedded: true

admin.mount_path (string, default: “/admin”)

URL path where embedded admin UI is accessible.

admin:
  embedded: true
  mount_path: "/mockforge-admin"

admin.standalone (boolean, default: true)

Force standalone admin UI server (overrides embedded setting).

admin:
  standalone: true

admin.disable_api (boolean, default: false)

Disable admin API endpoints while keeping the UI interface.

admin:
  disable_api: false

Validation Configuration

validation.mode (string, default: “enforce”)

Request validation mode. Options: “off”, “warn”, “enforce”

validation:
  mode: warn  # Log warnings but allow invalid requests

validation.aggregate_errors (boolean, default: false)

Combine multiple validation errors into a single JSON array response.

validation:
  aggregate_errors: true

validation.validate_responses (boolean, default: false)

Validate response payloads against OpenAPI schemas (warn-only).

validation:
  validate_responses: true

validation.status_code (integer, default: 400)

HTTP status code to return for validation errors.

validation:
  status_code: 422  # Use 422 Unprocessable Entity

validation.skip_admin_validation (boolean, default: true)

Skip validation for admin UI routes.

validation:
  skip_admin_validation: true

validation.overrides (object)

Per-route validation overrides.

validation:
  overrides:
    "/api/users": "off"      # Disable validation for this route
    "/api/admin/**": "warn"  # Warning mode for admin routes

Response Configuration

response.template_expand (boolean, default: false)

Enable template variable expansion in responses.

response:
  template_expand: true

response.caching (object)

Response caching configuration.

response:
  caching:
    enabled: true
    ttl_seconds: 300
    max_size_mb: 100

Chaos Engineering

chaos.latency_enabled (boolean, default: false)

Enable response latency simulation.

chaos:
  latency_enabled: true

chaos.latency_min_ms (integer, default: 0)

Minimum response latency in milliseconds.

chaos:
  latency_min_ms: 100

chaos.latency_max_ms (integer, default: 1000)

Maximum response latency in milliseconds.

chaos:
  latency_max_ms: 2000

chaos.failures_enabled (boolean, default: false)

Enable random failure injection.

chaos:
  failures_enabled: true

chaos.failure_rate (float, default: 0.0)

Probability of random failures (0.0 to 1.0).

chaos:
  failure_rate: 0.05  # 5% failure rate

chaos.failure_status_codes (array of integers)

HTTP status codes to return for injected failures.

chaos:
  failure_status_codes: [500, 502, 503, 504]

Full Chaos Engineering Surface (v0.3.125+)

The simple flat fields above are kept for back-compat. The richer chaos surface is configured under observability.chaos with these blocks:

observability.chaos.fault_injection

observability:
  chaos:
    enabled: true
    fault_injection:
      enabled: true

      # HTTP errors
      http_errors: [500, 502, 503, 504]
      http_error_probability: 0.1
      error_pattern:               # optional, takes precedence over flat probability
        type: burst                # burst | random | sequential
        count: 3
        interval_ms: 1000

      # Connection errors
      connection_errors: false
      connection_error_probability: 0.05
      connection_error_kind: http_503   # http_503 | tcp_reset | tcp_close

      # Real timeouts (sleep then 504)
      timeout_errors: false
      timeout_ms: 5000
      timeout_probability: 0.05

      # Truncated responses (chunked-aware)
      partial_responses: false
      partial_response_probability: 0.05

      # Body corruption
      payload_corruption: false
      payload_corruption_probability: 0.05
      corruption_type: none        # none | random_bytes | truncate | bit_flip

      # Per-request matcher: gate fault injection on request properties.
      # AND across fields, OR within a list. Empty matcher = match all.
      request_matcher:
        source_ips:
          - "10.0.0.0/8"
          - "192.168.1.42"
        headers:
          - name: "x-test"
            value: "yes"            # omit `value` for presence-only
        min_body_size_bytes: 1048576
        max_body_size_bytes: 10485760
        chunked_only: true

observability.chaos.rate_limit

rate_limit:
  enabled: true
  requests_per_second: 100
  burst_size: 10
  per_ip: true
  per_endpoint: false

observability.chaos.traffic_shaping

traffic_shaping:
  enabled: true
  bandwidth_limit_bps: 1000000   # 1 MB/s
  packet_loss_percent: 2.0
  max_connections: 100
  connection_timeout_ms: 30000

observability.chaos.circuit_breaker and bulkhead

circuit_breaker:
  enabled: true
  failure_threshold: 5
  success_threshold: 2
  timeout_ms: 60000

bulkhead:
  enabled: true
  max_concurrent_requests: 100
  max_queue_size: 10

For a tour of the resulting behavior — including which faults get injected per-request vs per-connection, and how connection_error_kind interacts with the chaos listener wrapper — see the Chaos Engineering chapter and the reference doc.

gRPC Configuration

grpc.proto_dir (string, default: “proto/”)

Directory containing Protocol Buffer files.

grpc:
  proto_dir: "my-protos/"

grpc.enable_reflection (boolean, default: true)

Enable gRPC server reflection for service discovery.

grpc:
  enable_reflection: true

grpc.excluded_services (array of strings)

gRPC services to exclude from automatic registration.

grpc:
  excluded_services:
    - "grpc.reflection.v1alpha.ServerReflection"

grpc.max_message_size (integer, default: 4194304)

Maximum message size in bytes (4MB default).

grpc:
  max_message_size: 8388608  # 8MB

grpc.concurrency_limit (integer, default: 32)

Maximum concurrent requests per connection.

grpc:
  concurrency_limit: 64

WebSocket Configuration

websocket.replay_file (string)

Path to WebSocket replay file for scripted interactions.

websocket:
  replay_file: "examples/ws-demo.jsonl"

websocket.max_connections (integer, default: 1000)

Maximum concurrent WebSocket connections.

websocket:
  max_connections: 500

websocket.message_timeout (integer, default: 30000)

Timeout for WebSocket messages in milliseconds.

websocket:
  message_timeout: 60000

websocket.heartbeat_interval (integer, default: 30000)

Heartbeat interval for long-running connections.

websocket:
  heartbeat_interval: 45000

Logging Configuration

logging.level (string, default: “info”)

Log level. Options: “error”, “warn”, “info”, “debug”, “trace”

logging:
  level: debug

logging.format (string, default: “text”)

Log output format. Options: “text”, “json”

logging:
  format: json

logging.file (string)

Path to log file (if not specified, logs to stdout).

logging:
  file: "/var/log/mockforge.log"

logging.max_size_mb (integer, default: 10)

Maximum log file size in megabytes before rotation.

logging:
  max_size_mb: 50

logging.max_files (integer, default: 5)

Maximum number of rotated log files to keep.

logging:
  max_files: 10

Complete Configuration Example

# Complete MockForge configuration example
server:
  http_port: 3000
  ws_port: 3001
  grpc_port: 50051
  bind: "0.0.0.0"

admin:
  enabled: true
  port: 9080
  embedded: false
  standalone: true

validation:
  mode: enforce
  aggregate_errors: false
  validate_responses: false
  status_code: 400

response:
  template_expand: true

chaos:
  latency_enabled: false
  failures_enabled: false

grpc:
  proto_dir: "proto/"
  enable_reflection: true
  max_message_size: 4194304

websocket:
  replay_file: "examples/ws-demo.jsonl"
  max_connections: 1000

logging:
  level: info
  format: text

Configuration Precedence

Configuration values are applied in order of priority (highest to lowest):

  1. Command-line arguments - Override all other settings
  2. Environment variables - Override config file settings
  3. Configuration file - Default values from YAML file
  4. Compiled defaults - Built-in fallback values

Environment Variable Mapping

A subset of config options can be overridden via env vars. The full list is in Environment Variables. Common ones:

# Server configuration
export MOCKFORGE_HTTP_PORT=9080
export MOCKFORGE_HTTP_HOST="127.0.0.1"
export MOCKFORGE_GRPC_PORT=50051
export MOCKFORGE_WS_PORT=3001

# Admin UI
export MOCKFORGE_ADMIN_ENABLED=true
export MOCKFORGE_ADMIN_PORT=9080

# Validation / templating
export MOCKFORGE_REQUEST_VALIDATION=warn
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

# Protocol-specific (paths)
export MOCKFORGE_WS_REPLAY_FILE="replay.jsonl"
# Use --grpc-proto-dir or grpc.proto_dir in YAML for proto paths

Validation

MockForge validates configuration files at startup and reports errors clearly:

# Validate configuration without starting server
mockforge-cli validate-config config.yaml

# Check for deprecated options
mockforge-cli validate-config --check-deprecated config.yaml

Hot Reloading

Some configuration options support runtime updates without restart:

  • Validation mode changes
  • Template expansion toggle
  • Admin UI settings
  • Logging level adjustments
# Update validation mode at runtime
curl -X POST http://localhost:9080/__mockforge/config \
  -H "Content-Type: application/json" \
  -d '{"validation": {"mode": "warn"}}'

Best Practices

Development Configuration

# development.yaml
server:
  http_port: 3000
  ws_port: 3001

admin:
  enabled: true
  embedded: true

validation:
  mode: warn

response:
  template_expand: true

logging:
  level: debug

Production Configuration

# production.yaml
server:
  http_port: 9080
  bind: "127.0.0.1"

admin:
  enabled: true
  standalone: true
  port: 9090

validation:
  mode: enforce

chaos:
  latency_enabled: false
  failures_enabled: false

logging:
  level: warn
  file: "/var/log/mockforge.log"

Testing Configuration

# test.yaml
server:
  http_port: 3000

validation:
  mode: off

response:
  template_expand: true

logging:
  level: debug

Migration Guide

Upgrading from CLI-only Configuration

If migrating from command-line only configuration:

  1. Create a config.yaml file with your current settings
  2. Test the configuration with mockforge-cli validate-config
  3. Gradually move settings from environment variables to the config file
  4. Update deployment scripts to use the config file

Version Compatibility

Configuration options may change between versions. Check the changelog for breaking changes and use the validation command to identify deprecated options:

mockforge-cli validate-config --check-deprecated config.yaml

This schema provides comprehensive control over MockForge’s behavior across all protocols and features.

Configuration Validation Guide

MockForge provides configuration validation to help you catch errors before starting the server. This guide explains how to validate your configuration and troubleshoot common issues.

Quick Start

Initialize a New Configuration

# Create a new project with template configuration
mockforge init my-project

# Or initialize in current directory
mockforge init .

This creates:

  • mockforge.yaml - Main configuration file
  • examples/ - Example OpenAPI spec and data files (unless --no-examples is used)

Validate Configuration

# Validate the current directory's config
mockforge config validate

# Validate a specific config file
mockforge config validate --config ./my-config.yaml

# Auto-discover config in parent directories
mockforge config validate

What Gets Validated

MockForge’s config validate command currently performs these checks:

1. File Existence

  • Checks if the config file exists
  • Auto-discovers mockforge.yaml or mockforge.yml in current and parent directories

2. YAML Syntax

  • Validates YAML syntax and structure
  • Reports parsing errors with line numbers

3. Basic Structure

  • Counts HTTP endpoints
  • Counts request chains
  • Warns about missing sections (HTTP, admin, WebSocket, gRPC)

4. Summary Report

✅ Configuration is valid

📊 Summary:
   Found 5 HTTP endpoints
   Found 2 chains

⚠️  Warnings:
   - No WebSocket configuration found

Manual Validation Checklist

Since validation is currently basic, here’s a manual checklist for comprehensive validation:

Required Fields

HTTP Configuration

http:
  port: 3000              # ✅ Required
  host: "0.0.0.0"        # ✅ Required

Admin Configuration

admin:
  enabled: true           # ✅ Required if using admin UI
  port: 9080             # ✅ Required in standalone mode

Common Mistakes

1. Invalid Port Numbers

# ❌ Wrong - port must be 1-65535
http:
  port: 70000

# ✅ Correct
http:
  port: 3000

2. Invalid File Paths

# ❌ Wrong - file doesn't exist
http:
  openapi_spec: "./nonexistent.json"

# ✅ Correct - verify file exists
http:
  openapi_spec: "./examples/openapi.json"

Test the path:

ls -la ./examples/openapi.json

3. Invalid Validation Mode

# ❌ Wrong - invalid mode
validation:
  mode: "strict"

# ✅ Correct - must be: off, warn, or enforce
validation:
  mode: "enforce"

4. Invalid Latency Configuration

# ❌ Wrong - base_ms is too high
core:
  default_latency:
    base_ms: 100000

# ✅ Correct - reasonable latency
core:
  default_latency:
    base_ms: 100
    jitter_ms: 50

5. Missing Required Fields in Routes

# ❌ Wrong - missing response status
http:
  routes:
    - path: /test
      method: GET
      response:
        body: "test"

# ✅ Correct - include status code
http:
  routes:
    - path: /test
      method: GET
      response:
        status: 200
        body: "test"

6. Invalid Environment Variable Names

# ❌ Wrong - incorrect prefix
export MOCK_FORGE_HTTP_PORT=3000

# ✅ Correct - use MOCKFORGE_ prefix
export MOCKFORGE_HTTP_PORT=3000

7. Conflicting Mount Path Configuration

# ❌ Wrong - both standalone and embedded
admin:
  enabled: true
  port: 9080
  mount_path: "/admin"    # Conflicts with standalone mode

# ✅ Correct - choose one mode
admin:
  enabled: true
  mount_path: "/admin"    # Embedded under HTTP server
  # OR
  port: 9080              # Standalone mode (no mount_path)

8. Advanced Validation Configuration

# ✅ Complete validation configuration
validation:
  mode: enforce                    # off | warn | enforce
  aggregate_errors: true          # Combine multiple errors
  validate_responses: false       # Validate response payloads
  status_code: 400                # Error status code (400 or 422)
  skip_admin_validation: true     # Skip validation for admin routes

  # Per-route overrides
  overrides:
    "GET /health": "off"          # Disable validation for health checks
    "POST /api/users": "warn"     # Warning mode for user creation
    "/api/internal/**": "off"     # Disable for internal endpoints

Validation Tools

1. YAML Syntax Validator

Use yamllint for syntax validation:

# Install yamllint
pip install yamllint

# Validate YAML syntax
yamllint mockforge.yaml

2. JSON Schema Validation (Future)

MockForge doesn’t currently provide JSON Schema validation, but you can use the template as a reference:

# Copy the complete template
cp config.template.yaml mockforge.yaml

# Edit with your settings, keeping structure intact

3. Test Your Configuration

The best validation is starting the server:

# Try to start the server
mockforge serve --config mockforge.yaml

# Check for error messages in logs

Troubleshooting

Error: “Configuration file not found”

Cause: Config file doesn’t exist or isn’t in expected location

Solution:

# Check current directory
ls -la mockforge.yaml

# Create from template
mockforge init .

# Or specify path explicitly
mockforge serve --config /path/to/config.yaml

Error: “Invalid YAML syntax”

Cause: YAML parsing error (usually indentation or quotes)

Solution:

# Use yamllint to find the exact error
yamllint mockforge.yaml

# Common fixes:
# - Fix indentation (use 2 spaces, not tabs)
# - Quote strings with special characters
# - Match opening/closing brackets and braces

Warning: “No HTTP configuration found”

Cause: Missing http: section

Solution:

# Add minimal HTTP config
http:
  port: 3000
  host: "0.0.0.0"

Error: “Port already in use”

Cause: Another process is using the configured port

Solution:

# Find what's using the port
lsof -i :3000

# Kill the process or change the port
# Change port in config:
http:
  port: 3001  # Use different port

OpenAPI Spec Not Loading

Cause: File path is incorrect or spec is invalid

Solution:

# Verify file exists
ls -la examples/openapi.json

# Validate OpenAPI spec at https://editor.swagger.io/
# Or use swagger-cli:
npm install -g @apidevtools/swagger-cli
swagger-cli validate examples/openapi.json

Best Practices

1. Use Version Control

# Track your config in Git
git add mockforge.yaml
git commit -m "Add MockForge configuration"

2. Environment-Specific Configs

# Create configs for different environments
mockforge.dev.yaml      # Development
mockforge.test.yaml     # Testing
mockforge.prod.yaml     # Production

# Use with:
mockforge serve --config mockforge.dev.yaml

3. Document Custom Settings

http:
  port: 3000

  # Custom validation override for legacy endpoint
  # TODO: Remove when v2 API is live
  validation_overrides:
    "POST /legacy/users": "off"

4. Start Simple, Add Complexity

# Start with minimal config
http:
  port: 3000
  openapi_spec: "./api.json"

admin:
  enabled: true

# Add features incrementally:
# 1. Template expansion
# 2. Latency simulation
# 3. Failure injection
# 4. Custom plugins

5. Use the Complete Template

# Copy the complete annotated template
cp config.template.yaml mockforge.yaml

# Remove sections you don't need
# Keep comments for reference

Complete Configuration Template

See the complete annotated configuration template for all available options with documentation.

Validation Roadmap

Future versions of MockForge will include:

  • JSON Schema Validation: Full schema validation for all fields
  • Field Type Checking: Validate types, ranges, and formats
  • Cross-Field Validation: Check for conflicts between settings
  • External Resource Validation: Verify files, URLs, and connections
  • Deprecation Warnings: Warn about deprecated options
  • Migration Assistance: Auto-migrate old configs to new formats

Track progress: MockForge Issue #XXX

Getting Help

Configuration not working as expected?

  1. Run mockforge config validate first
  2. Check the Configuration Schema Reference
  3. Review example configurations
  4. Ask on GitHub Discussions
  5. Report bugs at GitHub Issues

Pro Tip: Keep a backup of your working configuration before making significant changes. Use cp mockforge.yaml mockforge.yaml.backup before editing.

Supported Formats

MockForge supports various data formats for configuration, specifications, and data exchange. This reference documents all supported formats, their usage, and conversion utilities.

OpenAPI Specifications

MockForge supports OpenAPI 3.0/3.1 natively and Swagger / OpenAPI 2.0 via automatic up-conversion to 3.0 at import time (#838) — host/basePath/ schemes fold into servers, definitions become components/schemas, body/formData parameters become requestBody, and response schemas move under content. No external converter is needed.

JSON Format (Primary)

MockForge primarily supports OpenAPI 3.0+ specifications in JSON format:

{
  "openapi": "3.0.3",
  "info": {
    "title": "User API",
    "version": "1.0.0"
  },
  "paths": {
    "/users": {
      "get": {
        "summary": "List users",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/User"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {"type": "string"},
          "name": {"type": "string"},
          "email": {"type": "string"}
        }
      }
    }
  }
}

YAML Format (Alternative)

OpenAPI specifications can also be provided in YAML format:

openapi: 3.0.3
info:
  title: User API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string

Conversion Between Formats

# Convert JSON to YAML
node -e "
const fs = require('fs');
const yaml = require('js-yaml');
const spec = JSON.parse(fs.readFileSync('api.json', 'utf8'));
fs.writeFileSync('api.yaml', yaml.dump(spec));
"

# Convert YAML to JSON
node -e "
const fs = require('fs');
const yaml = require('js-yaml');
const spec = yaml.load(fs.readFileSync('api.yaml', 'utf8'));
fs.writeFileSync('api.json', JSON.stringify(spec, null, 2));
"

Protocol Buffers

.proto Files

gRPC services use Protocol Buffer definitions:

syntax = "proto3";

package myapp.user;

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);
  rpc CreateUser(CreateUserRequest) returns (User);
}

message GetUserRequest {
  string user_id = 1;
}

message User {
  string user_id = 1;
  string name = 2;
  string email = 3;
  google.protobuf.Timestamp created_at = 4;
}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
}

Generated Code

MockForge automatically generates Rust code from .proto files:

#![allow(unused)]
fn main() {
// Generated code structure
pub mod myapp {
    pub mod user {
        tonic::include_proto!("myapp.user");

        // Generated service trait
        #[tonic::async_trait]
        pub trait UserService: Send + Sync + 'static {
            async fn get_user(
                &self,
                request: tonic::Request<GetUserRequest>,
            ) -> Result<tonic::Response<User>, tonic::Status>;

            async fn list_users(
                &self,
                request: tonic::Request<ListUsersRequest>,
            ) -> Result<tonic::Response<Self::ListUsersStream>, tonic::Status>;
        }
    }
}
}

WebSocket Replay Files

JSONL Format

WebSocket interactions use JSON Lines format:

{"ts":0,"dir":"out","text":"Welcome to chat!","waitFor":"^HELLO$"}
{"ts":1000,"dir":"out","text":"How can I help you?"}
{"ts":2000,"dir":"out","text":"Please wait while I process your request..."}
{"ts":5000,"dir":"out","text":"Here's your response: ..."}

Extended JSONL with Templates

{"ts":0,"dir":"out","text":"Session {{uuid}} started at {{now}}"}
{"ts":1000,"dir":"out","text":"Connected to server {{server_id}}"}
{"ts":2000,"dir":"out","text":"{{#if authenticated}}Welcome back!{{else}}Please authenticate{{/if}}"}

Binary Message Support

{"ts":0,"dir":"out","text":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==","binary":true}
{"ts":1000,"dir":"out","text":"Image data sent"}

Configuration Files

YAML Configuration

MockForge uses YAML for configuration files:

# Server configuration
server:
  http_port: 3000
  ws_port: 3001
  grpc_port: 50051

# Validation settings
validation:
  mode: enforce
  aggregate_errors: false

# Response processing
response:
  template_expand: true

# Protocol-specific settings
grpc:
  proto_dir: "proto/"
  enable_reflection: true

websocket:
  replay_file: "examples/demo.jsonl"

JSON Configuration (Alternative)

Configuration can also be provided as JSON:

{
  "server": {
    "http_port": 3000,
    "ws_port": 3001,
    "grpc_port": 50051
  },
  "validation": {
    "mode": "enforce",
    "aggregate_errors": false
  },
  "response": {
    "template_expand": true
  },
  "grpc": {
    "proto_dir": "proto/",
    "enable_reflection": true
  },
  "websocket": {
    "replay_file": "examples/demo.jsonl"
  }
}

Data Generation Formats

JSON Output

Generated test data in JSON format:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]",
    "created_at": "2025-09-12T10:00:00Z"
  },
  {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "name": "Jane Smith",
    "email": "[email protected]",
    "created_at": "2025-09-12T11:00:00Z"
  }
]

YAML Output

Same data in YAML format:

- id: 550e8400-e29b-41d4-a716-446655440000
  name: John Doe
  email: [email protected]
  created_at: '2025-09-12T10:00:00Z'
- id: 550e8400-e29b-41d4-a716-446655440001
  name: Jane Smith
  email: [email protected]
  created_at: '2025-09-12T11:00:00Z'

CSV Output

Tabular data in CSV format:

id,name,email,created_at
550e8400-e29b-41d4-a716-446655440000,John Doe,[email protected],2025-09-12T10:00:00Z
550e8400-e29b-41d4-a716-446655440001,Jane Smith,[email protected],2025-09-12T11:00:00Z

Log Formats

Text Format (Default)

Human-readable log output:

2025-09-12T10:00:00Z INFO mockforge::http: Server started on 0.0.0.0:3000
2025-09-12T10:00:01Z INFO mockforge::http: Request: GET /users
2025-09-12T10:00:01Z DEBUG mockforge::template: Template expanded: {{uuid}} -> 550e8400-e29b-41d4-a716-446655440000
2025-09-12T10:00:01Z INFO mockforge::http: Response: 200 OK

JSON Format

Structured JSON logging:

{"timestamp":"2025-09-12T10:00:00Z","level":"INFO","module":"mockforge::http","message":"Server started on 0.0.0.0:3000"}
{"timestamp":"2025-09-12T10:00:01Z","level":"INFO","module":"mockforge::http","message":"Request: GET /users","method":"GET","path":"/users","user_agent":"curl/7.68.0"}
{"timestamp":"2025-09-12T10:00:01Z","level":"DEBUG","module":"mockforge::template","message":"Template expanded","template":"{{uuid}}","result":"550e8400-e29b-41d4-a716-446655440000"}
{"timestamp":"2025-09-12T10:00:01Z","level":"INFO","module":"mockforge::http","message":"Response: 200 OK","status":200,"duration_ms":15}

Template Syntax

Handlebars Templates

MockForge uses Handlebars-style templates:

{{variable}}
{{object.property}}
{{array.[0]}}
{{#if condition}}content{{/if}}
{{#each items}}{{this}}{{/each}}
{{helper arg1 arg2}}

Built-in Helpers

<!-- Data generation -->
{{uuid}}                    <!-- Random UUID -->
{{now}}                     <!-- Current timestamp -->
{{now+1h}}                  <!-- Future timestamp -->
{{randInt 1 100}}          <!-- Random integer -->
{{randFloat 0.0 1.0}}      <!-- Random float -->
{{randWord}}               <!-- Random word -->
{{randSentence}}           <!-- Random sentence -->
{{randParagraph}}          <!-- Random paragraph -->

<!-- Request context -->
{{request.path.id}}        <!-- URL path parameter -->
{{request.query.limit}}    <!-- Query parameter -->
{{request.header.auth}}    <!-- HTTP header -->
{{request.body.name}}      <!-- Request body field -->

<!-- Logic helpers -->
{{#if user.authenticated}}
  Welcome back, {{user.name}}!
{{else}}
  Please log in.
{{/if}}

{{#each users}}
  <li>{{name}} - {{email}}</li>
{{/each}}

Conversion Utilities

Format Conversion Scripts

#!/bin/bash
# convert-format.sh - Convert between supported formats

input_file=$1
output_format=$2

case $output_format in
    "yaml")
        python3 -c "
import sys, yaml, json
data = json.load(sys.stdin)
yaml.dump(data, sys.stdout, default_flow_style=False)
" < "$input_file"
        ;;
    "json")
        python3 -c "
import sys, yaml, json
data = yaml.safe_load(sys.stdin)
json.dump(data, sys.stdout, indent=2)
" < "$input_file"
        ;;
    "xml")
        python3 -c "
import sys, json, dicttoxml
data = json.load(sys.stdin)
xml = dicttoxml.dicttoxml(data, custom_root='root', attr_type=False)
print(xml.decode())
" < "$input_file"
        ;;
    *)
        echo "Unsupported format: $output_format"
        echo "Supported: yaml, json, xml"
        exit 1
        ;;
esac

Validation Scripts

#!/bin/bash
# validate-format.sh - Validate file formats

file=$1
format=$(basename "$file" | sed 's/.*\.//')

case $format in
    "json")
        python3 -c "
import sys, json
try:
    json.load(sys.stdin)
    print('✓ Valid JSON')
except Exception as e:
    print('✗ Invalid JSON:', e)
    sys.exit(1)
" < "$file"
        ;;
    "yaml")
        python3 -c "
import sys, yaml
try:
    yaml.safe_load(sys.stdin)
    print('✓ Valid YAML')
except Exception as e:
    print('✗ Invalid YAML:', e)
    sys.exit(1)
" < "$file"
        ;;
    "xml")
        python3 -c "
import sys, xml.etree.ElementTree as ET
try:
    ET.parse(sys.stdin)
    print('✓ Valid XML')
except Exception as e:
    print('✗ Invalid XML:', e)
    sys.exit(1)
" < "$file"
        ;;
    *)
        echo "Unsupported format: $format"
        exit 1
        ;;
esac

Best Practices

Choosing the Right Format

Use CaseRecommended FormatReason
API SpecificationsOpenAPI YAMLMore readable, better for version control
ConfigurationYAMLHuman-readable, supports comments
Data ExchangeJSONUniversally supported, compact
LogsJSONStructured, searchable
TemplatesHandlebarsExpressive, logic support

Format Conversion Workflow

# API development workflow
# 1. Design API in YAML (readable)
swagger-editor

# 2. Convert to JSON for tools that require it
./convert-format.sh api.yaml json > api.json

# 3. Validate both formats
./validate-format.sh api.yaml
./validate-format.sh api.json

# 4. Generate documentation
swagger-codegen generate -i api.yaml -l html -o docs/

# 5. Commit YAML version (better diff)
git add api.yaml

Performance Considerations

  • JSON: Fastest parsing, smallest size
  • YAML: Slower parsing, larger size, better readability
  • XML: Slowest parsing, largest size, most verbose
  • Binary formats: Fastest for large data, not human-readable

Compatibility Matrix

FormatMockForge SupportReadabilityTool SupportSize
JSON✅ FullMediumExcellentSmall
YAML✅ FullHighGoodMedium
XML❌ NoneLowGoodLarge
Protocol Buffers✅ gRPC onlyLowLimitedSmall
JSONL✅ WebSocketMediumBasicMedium

This format reference ensures you can work effectively with all data formats supported by MockForge across different use cases and workflows.

Templating Reference

MockForge supports lightweight templating across HTTP responses, overrides, and (soon) WS/gRPC). This page documents all supported tokens and controls.

Enabling

  • Environment: MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true|false (default: false)
  • Config: http.response_template_expand: true|false
  • CLI: --response-template-expand
  • Determinism: MOCKFORGE_FAKE_TOKENS=false disables faker token expansion.

Time Tokens

  • {{now}} — RFC3339 timestamp.
  • {{now±And|Nh|Nm|Ns}} — Offset from now by Days/Hours/Minutes/Seconds.
    • Examples: {{now+2h}}, {{now-30m}}, {{now+10s}}, {{now-1d}}.

Random Tokens

  • {{rand.int}} — random integer in [0, 1_000_000].
  • {{rand.float}} — random float in [0,1).
  • {{randInt a b}} / {{rand.int a b}} — random integer between a and b (order-agnostic, negatives allowed).
    • Examples: {{randInt 10 99}}, {{randInt -5 5}}.

UUID

  • {{uuid}} — UUID v4.

Request Data Access

  • {{request.body.field}} — Access fields from request body JSON.
    • Example: {{request.body.name}} extracts the name field from request body.
  • {{request.path.param}} — Access path parameters.
    • Example: {{request.path.id}} extracts the id path parameter.
  • {{request.query.param}} — Access query parameters.
    • Example: {{request.query.limit}} extracts the limit query parameter.

Faker Tokens

Faker expansions can be disabled via MOCKFORGE_FAKE_TOKENS=false.

  • Minimal (always available): {{faker.uuid}}, {{faker.email}}, {{faker.name}}.
  • Extended (when feature data-faker is enabled):
    • {{faker.address}}, {{faker.phone}}, {{faker.company}}, {{faker.url}}, {{faker.ip}}
    • {{faker.color}}, {{faker.word}}, {{faker.sentence}}, {{faker.paragraph}}

Where Templating Applies

  • HTTP (OpenAPI): media-level example bodies and synthesized responses.
  • HTTP Overrides: YAML patches loaded via validation_overrides.
  • WS/gRPC: provider is registered now; expansion hooks will be added as features land.

Status Codes for Validation Errors

  • MOCKFORGE_VALIDATION_STATUS=400|422 (default 400). Affects HTTP request validation failures in enforce mode.

Security & Determinism Notes

  • Tokens inject random/time-based values; disable faker to reduce variability.
  • For deterministic integration tests, set MOCKFORGE_FAKE_TOKENS=false and prefer explicit literals.

Request Chaining

MockForge supports request chaining, which allows you to create complex workflows where requests can depend on responses from previous requests in the chain. This is particularly useful for testing API workflows that require authentication, data flow between endpoints, or multi-step operations.

Overview

Request chaining enables you to:

  • Execute requests in a predefined sequence with dependencies
  • Reference data from previous responses using template variables
  • Extract and store specific values from responses for reuse
  • Validate response status codes and content
  • Implement parallel execution for independent requests
  • Handle complex authentication and authorization flows

Chain Definition

Chains are defined using YAML or JSON configuration files with the following structure:

id: my-chain
name: My Chain
description: A description of what this chain does
config:
  enabled: true
  maxChainLength: 20
  globalTimeoutSecs: 300
  enableParallelExecution: false
links:
  # Define your requests here
  - request:
      id: step1
      method: POST
      url: https://api.example.com/auth/login
      headers:
        Content-Type: application/json
      body:
        username: "testuser"
        password: "password123"
    extract:
      token: body.access_token
    storeAs: login_response
    dependsOn: []
variables:
  base_url: https://api.example.com
tags:
  - authentication
  - workflow

Chain Configuration

The config section controls how the chain behaves:

FieldTypeDefaultDescription
enabledbooleanfalseWhether this chain is enabled
maxChainLengthinteger20Maximum number of requests in the chain
globalTimeoutSecsinteger300Total timeout for chain execution
enableParallelExecutionbooleanfalseEnable parallel execution of independent requests

Each link in the chain defines a single HTTP request and its behavior:

Request Definition

FieldTypeRequiredDescription
idstringYesUnique identifier for this request
methodstringYesHTTP method (GET, POST, PUT, DELETE, etc.)
urlstringYesRequest URL (supports template variables)
headersobjectNoRequest headers
bodyanyNoRequest body (supports template variables)
dependsOnarrayNoList of request IDs this request depends on
timeoutSecsnumberNoIndividual request timeout
expectedStatusarrayNoExpected status codes for validation

Response Processing

FieldTypeRequiredDescription
extractobjectNoExtract values from response into variables
storeAsstringNoStore entire response with this name

Template Variables

Chain requests support powerful templating that can reference:

Previous Response Data

Use {{chain.<response_name>.<path>}} to reference data from previous responses:

url: https://api.example.com/users/{{chain.login_response.body.user_id}}/posts
headers:
  Authorization: "Bearer {{chain.auth_response.body.access_token}}"

Variable Extraction

Extract values from responses into reusable variables:

extract:
  user_id: body.user.id
  token: body.access_token
storeAs: user_response

Built-in Template Functions

All standard MockForge templating functions are available:

  • {{uuid}} - Random UUID
  • {{faker.email}} - Fake email address
  • {{faker.name}} - Fake name
  • {{rand.int}} - Random integer
  • {{now}} - Current timestamp

Advanced Features

Dependency Resolution

Requests can depend on other requests using the dependsOn field. MockForge automatically resolves dependencies using topological sorting:

links:
  - request:
      id: login
      method: POST
      url: https://api.example.com/auth/login
      body:
        username: "user"
        password: "pass"
    storeAs: auth

  - request:
      id: get_profile
      method: GET
      url: https://api.example.com/user/profile
      headers:
        Authorization: "Bearer {{chain.auth.body.token}}"
    dependsOn:
      - login

Parallel Execution

Enable enableParallelExecution: true to allow independent requests to run simultaneously:

config:
  enableParallelExecution: true
links:
  - request:
      id: get_profile
      method: GET
      url: https://api.example.com/profile
    dependsOn:
      - login

  - request:
      id: get_preferences
      method: GET
      url: https://api.example.com/preferences
    dependsOn:
      - login
  # These two requests will run in parallel

Response Validation

Validate response status codes and content:

links:
  - request:
      id: create_user
      method: POST
      url: https://api.example.com/users
      body:
        name: "John Doe"
    expectedStatus: [201, 202]  # Expect 201 or 202 status codes

JSON Path Support

Chain templating supports JSON path syntax for accessing nested data:

Simple Properties

extract:
  user_id: body.id
  name: body.profile.name

Array Access

extract:
  first_user: body.users.[0].name
  user_count: body.users.[*]  # Get array length

Complex Nesting

url: https://api.example.com/users/{{chain.login_response.body.user.id}}/projects/{{chain.project_response.body.data.[0].id}}

Response Function (New UI Feature)

MockForge also supports a response() function for use in the Admin UI and other editing contexts:

Syntax

response('request_name', 'json_path')

Examples

// Simple usage
response('login', 'body.user_id')

// Complex JSON path
response('user_profile', 'body.data.employee.name')

// Environment variable usage
let userId = response('login', 'body.user_id');
let updateUrl = `/users/${userId}/profile`;

UI Integration

  1. Autocomplete: Type response( in any input field in the UI and use Ctrl+Space for autocomplete
  2. Configuration Dialog: Click the blue template tag next to the function to open the configuration dialog
  3. Request Selection: Choose from available requests in the current chain
  4. Path Specification: Enter the JSONPath to extract the desired value

Pre/Post Request Scripting

MockForge supports JavaScript scripting for complex request processing and data manipulation in request chains.

Enable Scripting

Add scripting configuration to any request in your chain:

links:
  - request:
      id: process_data
      method: POST
      url: https://api.example.com/process
      scripting:
        pre_script: |
          // Execute before request
          console.log('Processing request with mockforge context');
          console.log('Request URL:', mockforge.request.url);

          if (mockforge.variables.skip_processing) {
            request.body.skip_processing = true;
          }
        post_script: |
          // Execute after request
          console.log('Request completed in', mockforge.response.duration_ms, 'ms');

          if (mockforge.response.status === 429) {
            throw new Error('Rate limited - retry needed');
          }

          // Store custom data for next request
          setVariable('processed_user_id', mockforge.response.body.user_id);
        runtime: javascript
        timeout_ms: 5000

Pre-Scripts

Executed before the HTTP request:

// Available context in mockforge object:
mockforge.request     // Current request (id, method, url, headers)
mockforge.chain       // Previous responses: mockforge.chain.login.body.user_id
mockforge.variables   // Chain variables
mockforge.env         // Environment variables

// Direct access to functions:
console.log('Starting request processing');

// Modify request before it goes out
if (mockforge.variables.enable_debug) {
  request.headers['X-Debug'] = 'true';
  request.body.debug_mode = true;
}

// Set variables for this request
setVariable('request_start_time', Date.now());

// Example: Add authentication from previous response
request.headers['Authorization'] = 'Bearer ' + mockforge.chain.login.body.token;

Post-Scripts

Executed after the HTTP response:

// Available context in mockforge object:
mockforge.response    // Current response (status, headers, body, duration_ms)
mockforge.request     // Original request
mockforge.chain       // Previous responses
mockforge.variables   // Chain variables
mockforge.env         // Environment variables

// Example: Validate response and extract data
if (mockforge.response.status !== 200) {
  throw new Error('Request failed with status ' + mockforge.response.status);
}

// Extract and store data for next requests
setVariable('user_profile', mockforge.response.body);
setVariable('session_cookie', mockforge.response.headers['Set-Cookie']);

// Example: Transform response data
if (mockforge.response.body && mockforge.response.body.user) {
  mockforge.response.body.processed_user = {
    fullName: mockforge.response.body.user.first_name + ' ' + mockforge.response.body.user.last_name,
    age: mockforge.response.body.user.age,
    isActive: mockforge.response.body.user.status === 'active'
  };
}

Built-in Functions

Logging and Diagnostics

console.log('Debug message:', mockforge.request.url);
console.warn('Warning:', mockforge.response.status);
console.error('Error occurred');

Variable Management

// Set a variable for use in next requests
setVariable('api_token', mockforge.response.body.token);

// Access environment variables
const configUrl = mockforge.env['API_CONFIG_URL'];

Data Validation

// Simple assertions
assert(mockforge.response.status === 200, 'Expected status 200');

// Complex validation
if (!mockforge.response.body || !mockforge.response.body.items) {
  throw new Error('Response missing required "items" field');
}

if (mockforge.response.body.items.length === 0) {
  console.warn('Response contains empty items array');
}

Error Handling

Scripts can throw errors to fail the chain:

if (mockforge.response.status >= 400) {
  throw new Error('HTTP ' + mockforge.response.status + ': ' + mockforge.response.body.error);
}

if (mockforge.response.duration_ms > 30000) {
  throw new Error('Request took too long: ' + mockforge.response.duration_ms + 'ms');
}

Security and Isolation

  • Timeout Protection: Scripts are limited by timeout_ms (default: 5 seconds)
  • Sandboxing: Scripts run in isolated JavaScript contexts
  • Resource Limits: CPU and memory usage is monitored and limited
  • Network Restrictions: Scripts cannot make outbound network calls
  • File System Access: Read-only file access through fs.readFile() function

Best Practices

  1. Keep Scripts Simple: Break complex logic into smaller, focused scripts
  2. Validate Inputs: Always check that expected data exists before processing
  3. Set Appropriate Timeouts: Use shorter timeouts for simple scripts
  4. Use Environment Variables: Store configuration in environment variables
  5. Error Handling: Always check for error conditions and fail fast when needed
  6. Documentation: Comment complex business logic in your scripts
  7. Testing: Test scripts with various response scenarios

Environment Variables

For multiple uses of the same response value, store it in an environment variable:

// In environment variables
RESPONSE_USER_ID = response('login', 'body.user_id')

// Then use in multiple places
let url1 = `/users/${RESPONSE_USER_ID}`;
let url2 = `/profile/${RESPONSE_USER_ID}`;

Benefits Over Traditional Templates

  • Cleaner Syntax: More readable than {{chain.request_name.body.path}}
  • Type Safety: JSONPath validation in the UI
  • Better UX: Visual configuration through dialogs
  • Autocomplete: Intelligent suggestions for request names and paths

Error Handling

Chains provide comprehensive error handling:

  • Dependency errors: Missing or invalid dependencies
  • Circular dependencies: Automatic detection and prevention
  • Timeout errors: Individual and global timeouts
  • Status validation: Expected status code validation
  • Network errors: Connection and HTTP errors

Chain Management

Chains can be managed programmatically or via configuration files:

Loading Chains

#![allow(unused)]
fn main() {
use mockforge_core::RequestChainRegistry;

let registry = RequestChainRegistry::new(chain_config);
// Load from YAML
registry.register_from_yaml(yaml_content).await?;
// Load from JSON
registry.register_from_json(json_content).await?;
}

Executing Chains

#![allow(unused)]
fn main() {
use mockforge_core::ChainExecutionEngine;

let engine = ChainExecutionEngine::new(registry, config);
// Execute a chain
let result = engine.execute_chain("my-chain").await?;
println!("Chain executed in {}ms", result.total_duration_ms);
}

Complete Example

See the provided examples in the examples/ directory:

  • examples/chain-example.yaml - Comprehensive user management workflow
  • examples/simple-chain.json - Simple authentication chain

Working With Large Values

MockForge provides several strategies to handle large values efficiently without affecting performance or crashing the user interface. The system automatically hides large text values by default, but extremely large values can still impact performance.

File System Template Functions

MockForge supports the fs.readFile() template function for reading file contents directly into templates. This is particularly useful for including large text content within structured data.

Syntax:

{{fs.readFile "path/to/file.txt"}}
{{fs.readFile('path/to/file.txt')}}

Example usage in request chaining:

links:
  - request:
      id: upload_large_data
      method: POST
      url: https://api.example.com/upload
      headers:
        Content-Type: application/json
      body:
        metadata:
          filename: "large_document.txt"
          size: 1048576
        content: "{{fs.readFile('/path/to/large/file.txt')}}"

Error handling:

  • If the file doesn’t exist: <fs.readFile error: No such file or directory (os error 2)>
  • If the path is empty: <fs.readFile: empty path>

Binary File Request Bodies

For truly large binary files (images, videos, documents), MockForge supports binary file request bodies that reference files on disk rather than loading them into memory.

YAML Configuration:

links:
  - request:
      id: upload_image
      method: POST
      url: https://api.example.com/upload
      body:
        type: binary_file
        data:
          path: "/path/to/image.jpg"
          content_type: "image/jpeg"

JSON Configuration:

{
  "id": "upload_image",
  "method": "POST",
  "url": "https://api.example.com/upload",
  "body": {
    "type": "binary_file",
    "data": {
      "path": "/path/to/image.jpg",
      "content_type": "image/jpeg"
    }
  }
}

Key Features:

  • Path templating: File paths support template expansion (e.g., "{{chain.previous_response.body.file_path}}")
  • Content type: Optional content-type header (defaults to none for binary files)
  • Memory efficient: Files are read only when the request is executed
  • Error handling: Clear error messages for missing files

Performance Best Practices

  1. Use binary_file for large binary content (images, videos, large documents)
  2. Use fs.readFile for large text content within structured JSON/XML bodies
  3. Template file paths to make configurations dynamic
  4. Validate file paths before running chains to avoid runtime errors
  5. Consider file size limits based on your system’s memory constraints

Best Practices

  1. Keep chains focused: Each chain should have a single, clear purpose
  2. Use meaningful IDs: Choose descriptive names for requests and chains
  3. Handle dependencies carefully: Ensure dependency chains are logical and avoid cycles
  4. Validate responses: Use expectedStatus and extract for critical paths
  5. Use parallel execution: Enable for independent requests to improve performance
  6. Template effectively: Leverage chain context variables for dynamic content
  7. Error handling: Plan for failure scenarios in your chains
  8. Handle large values efficiently: Use fs.readFile() for large text content and binary_file request bodies for large binary files to maintain performance

Limitations

  • Maximum chain length is configurable (default: 20 requests)
  • Global execution timeout applies to entire chain
  • Circular dependencies are automatically prevented
  • Parallel execution requires careful dependency management

Fixtures and Smoke Testing

MockForge supports recording and replaying HTTP requests and responses as fixtures, which can be used for smoke testing your APIs.

Recording Fixtures

Recording is enabled via the --record CLI flag or core.fixtures.record: true in YAML. By default all HTTP requests are recorded. To record only GET requests, set core.fixtures.record_get_only: true. Fixtures are saved in MOCKFORGE_FIXTURES_DIR (default ./fixtures).

Replay Fixtures

Replay is enabled via the --replay CLI flag or core.fixtures.replay: true in YAML. When replay is enabled, MockForge serves recorded responses for matching requests instead of generating new ones.

Ready-to-Run Fixtures

Fixtures can be marked as “ready-to-run” for smoke testing by adding a metadata field smoke_test with the value true. These fixtures will be listed in the smoke test endpoints.

Example fixture with smoke test metadata:

{
  "fingerprint": {
    "method": "GET",
    "path": "/api/users",
    "query_params": {},
    "headers": {}
  },
  "timestamp": "2024-01-15T10:30:00Z",
  "status_code": 200,
  "response_headers": {
    "content-type": "application/json"
  },
  "response_body": "{\"users\": []}",
  "metadata": {
    "smoke_test": "true",
    "name": "Get Users Endpoint"
  }
}

Smoke Testing

MockForge provides endpoints to list and run smoke tests:

  • GET /__mockforge/smoke - List available smoke test endpoints
  • GET /__mockforge/smoke/run - Run all smoke tests

These endpoints are also available in the Admin UI under the “Smoke Tests” tab.

Admin UI Integration

The Admin UI provides a graphical interface for managing fixtures and running smoke tests:

  1. View all recorded fixtures in the “Fixtures” tab
  2. Mark fixtures as ready-to-run for smoke testing
  3. Run smoke tests with a single click
  4. View smoke test results and status

Configuration

The following environment variables control fixture and smoke test behavior:

Core Settings (env vars)

  • MOCKFORGE_FIXTURES_DIR - Directory where fixtures are stored (default: ./fixtures)
  • MOCKFORGE_LATENCY_ENABLED - Inject latency on responses (default: false)
  • MOCKFORGE_RESPONSE_TEMPLATE_EXPAND - Expand {{...}} templates in responses (default: false)
  • MOCKFORGE_REQUEST_VALIDATION - Validation level for incoming requests (enforce | warn | off)
  • MOCKFORGE_RESPONSE_VALIDATION - Validate generated responses against the spec (true | false)

Record / replay toggles (CLI / YAML, not env)

record_enabled, replay_enabled, and record_get_only are configured under core.fixtures.* in YAML or via the --record / --replay CLI flags — they don’t have env-var equivalents.

Configuration File Support

You can also configure fixtures through YAML:

# In your configuration file
core:
  fixtures:
    dir: "./fixtures"
    record_enabled: false
    replay_enabled: false
    record_get_only: false

Conformance self-test probe reference

The mockforge bench --conformance-self-test driver runs a positive case plus one probe per category against every operation in the spec, and records the result in conformance-self-test.json (plus a human- readable summary in conformance-report.html).

This page is the canonical reference for every probe label the driver can emit. Use it to interpret the negative_caught / negative_missed buckets in the JSON, and the “Missed negatives” drill-down in the HTML report.

Label scheme

<category>:<subcategory>[:<scope>]

The category (the part before the first :) is what the report buckets on. So request-body:type-mismatch:user.email rolls up under request-body, alongside request-body:empty, request-body:required-removed:id, and friends.

Per-location violation entries (#896)

Server-side violation buffer entries are emitted one per location, not one per request. A single POST that fails a query enum (kind) AND a required body field (email) produces:

{ "category": "query",         "reason": "kind: Validation error ...",  "occurrences": 1 }
{ "category": "request-body",  "reason": "email: ... is required",      "occurrences": 1 }
  • category mirrors the validator detail’s "path" prefix: query / headers / cookies / parameters (path params) / request-body.
  • reason starts with the offending parameter or field name, so grepping query.\$.xgafv-style details works directly against the export.
  • With dedup enabled (MOCKFORGE_CONFORMANCE_BUFFER_UNIQUE=true, default), same (method, path, category, reason) repeats collapse into one entry with a bumped occurrences.
  • Requests whose validator output carries no structured per-location details[] fall back to the legacy one-entry-per-request shape with the priority classifier (classify_validation_reason).

Positive case (one per operation)

LabelWhat it sendsExpected status
positiveThe spec-derived sample body, plus all required path / query / header parameters2xx or 3xx

A missed positive (4xx/5xx) means the server rejected a request the spec says is valid. Common cause: missing auth header, missing --base-path, or a spec-derived sample that doesn’t satisfy a non-trivial constraint the synthesiser didn’t notice.

Request-body negatives

Fire whenever the operation declares a request body content type.

LabelWhat it sendsExpectedMiss =
request-body:empty{}4xxValidator allows missing required fields
request-body:wrong-type[] instead of {}4xxValidator doesn’t enforce top-level shape
request-body:type-mismatch:$roottop-level shape swap (object→array etc.)4xxValidator’s root-level type check is permissive
request-body:type-mismatch:<field>per-field type swap (string→number etc.)4xxValidator doesn’t enforce field type
request-body:required-removed:<field>drops a required field (one at a time, cap 5)4xxValidator doesn’t enforce requiredness
request-body:min-length:<field>string below minLength4xxminLength constraint not enforced
request-body:max-length:<field>string above maxLength4xxmaxLength constraint not enforced
request-body:pattern:<field>string that doesn’t match pattern regex4xxpattern constraint not enforced
request-body:enum-out-of-range:<field>value not in enum4xxenum constraint not enforced
request-body:min:<field>numeric below minimum4xxminimum constraint not enforced
request-body:max:<field>numeric above maximum4xxmaximum constraint not enforced
request-body:integer-as-float:<field>1.5 for integer-typed field4xxInteger vs number distinction not enforced
request-body:additional-property:$rootextra field when additionalProperties: false4xxadditionalProperties: false not enforced

Bounded at SCHEMA_MUTATION_CAP = 12 mutations per operation (top 20 properties, top 5 required) so a 100-property body on a 22 000-op spec doesn’t produce a runaway test matrix.

Content-type negatives (rounds 27 / 28 / 32)

Fire on operations that declare application/json as an accepted request-body content type. Each variant covers one way a real client can get the content-type vs the body wrong.

LabelWhat it sendsExpectedMiss =
request-body:content-type-mismatch:xmlspec-shape JSON body, Content-Type: application/xml header415Server didn’t enforce Content-Type
request-body:content-type-mismatch:yamlspec-shape JSON body, Content-Type: application/yaml415as above
request-body:content-type-mismatch:multipartspec-shape JSON body, Content-Type: multipart/form-data415as above
request-body:content-type-mismatch:urlencodedspec-shape JSON body, Content-Type: application/x-www-form-urlencoded415as above

Round 28 wired these into the shared ServerConformanceViolation buffer so the server-side report also records when a server accepts the mismatched content-type, not just the client-side bench.

Variant-b: embedded non-JSON content

Companion probes (round 27) inject an XML / YAML / multipart / urlencoded snippet into the first string field of a spec-shape JSON envelope. The Content-Type header stays application/json and the body parses as valid JSON; only the string-valued payload changes.

Round 35 made these tolerate 4xx server responses, because a server with a pattern / format validator on the target field will (correctly) reject the embedded snippet. That’s why the expected range is 2xx-4xx: only a 5xx is a finding (server crashed parsing the embedded payload).

LabelWhat it sendsExpectedMiss =
request-body:embedded-content:xml{"<first-string-field>": "<root>...</root>"}2xx-4xx5xx only: server crashed parsing the embedded XML
request-body:embedded-content:yamlsame shape, YAML-shaped snippet2xx-4xx5xx only: server crashed parsing the embedded YAML
request-body:embedded-content:multipartsame shape, multipart-shaped snippet2xx-4xx5xx only: server crashed parsing the embedded multipart
request-body:embedded-content:urlencodedsame shape, urlencoded-shaped snippet2xx-4xx5xx only: server crashed parsing the embedded urlencoded

Round 34 skips these probes entirely when the positive sample has no string leaf to mutate (e.g. a {enabled: boolean} body), so the bench doesn’t emit a probe it knows can’t construct a valid envelope.

Parameter negatives

LabelWhat it sendsExpectedMiss =
parameters:missing-querydrops the first required query parameter4xxRequired query param check missing
parameters:missing-headerdrops the first required header parameter4xxRequired header check missing
parameters:bad-path-paramsubstitutes the first path param with self-test-invalid-id4xxPath-param type / format / pattern not enforced (or the spec is intentionally permissive)
parameters:uri-too-longappends a 9 KiB query string4xxURI length cap not enforced; OK on many servers, but a deployment behind a tight reverse-proxy cap should reject

Security negatives (only when the spec declares a security scheme)

LabelWhat it sendsExpectedMiss =
security:bad-bearerAuthorization: Bearer self-test-invalid-token4xx (401/403)Bearer auth not enforced
security:bad-basicAuthorization: Basic <base64-of-self-test:invalid>4xxBasic auth not enforced
security:bad-apikey:<name>junk value in the declared header / query / cookie4xxAPI-key check missing for <name>
security:no-authstrips Authorization + any declared API-key header / query / cookie4xxAuth absence not enforced (route is effectively public)

Auth-stripping is case-insensitive on Authorization and walks the operation’s own declared API-key locations, so the probe’s credential is the only thing the server sees.

OWASP injection negatives

Fire only when the operation has an injectable target. Target is chosen once per operation in priority order:

  1. First query parameter’s value
  2. First string field of the positive JSON body
  3. Skip — no false signal for GET /healthz
LabelCanonical payloadExpectedMiss =
owasp:sqli' OR '1'='14xxInput sanitiser missed SQL metacharacters
owasp:xss<script>alert('XSS')</script>4xxHTML / JS payload not rejected
owasp:command-injectionshell metacharacter payload4xxShell-escape not enforced
owasp:path-traversal../../etc/passwd style payload4xxPath-traversal not enforced
owasp:ssti{{7*7}} style template payload4xxServer-side template injection surface
owasp:ldap-injection*)(uid=* style payload4xxLDAP filter not escaped
owasp:xxe<!DOCTYPE … SYSTEM …> XML payload4xxXXE surface

A 5xx on any OWASP probe is a hard finding (server crashed on the payload). A 2xx is a soft finding (input passed through unfiltered; may or may not be a real vulnerability depending on whether the payload reaches a sink).

How “passed” is decided

Currently response-code-only. Each probe records the expected status range it was designed for (CaseCapture.expected_status_range) and the driver compares the actual HTTP status against that range. The driver uses a tristate ExpectedOutcome enum (round 35):

ExpectedOutcomeexpected_status_rangepassed is true when
Success2xx-3xx(200..400).contains(&status)
ClientError4xx(400..500).contains(&status)
NotServerError2xx-4xx(200..500).contains(&status) (only 5xx fails)

Probe-by-probe assignment:

  • Positive case → Success → 2xx-3xx.
  • All request-body / parameter / security / OWASP negatives → ClientError → 4xx.
  • content-type-mismatch:* negatives → ClientError → expected 415, evaluated as 4xx.
  • embedded-content:* (variant-b) negatives → NotServerError → 2xx-4xx.

A response-body shape validator (in addition to the status-code check) is queued (round 21.3).

5xx is always a finding

The bench never deliberately elicits a 5xx. None of the probe families above expect or tolerate a 5xx. A server emitting 5xx on any probe is a server-side bug to fix, not a noisy test result. That’s true for the NotServerError variants too: the 2xx-4xx tolerance still treats 5xx as a fail.

What --inject-response-violations changes

This flag is sometimes confused with status-class chaos. It is narrowly scoped to response bodies:

  • Modifies the response body for synthesized 2xx responses by dropping the first declared required field from the response schema, so the body becomes spec-non-conforming while still parsing as JSON.
  • Does not change the HTTP status. A 2xx response stays 2xx; a 4xx response stays 4xx.
  • Use case: feed a downstream proxy or conformance harness a known bad-shape body so you can confirm it catches the mismatch.

If you want to exercise downstream handling of varied 4xx / 5xx statuses, use the chaos surface instead:

  • mockforge serve --chaos — global random failure injection with configurable per-status weight.
  • The route-chaos API under /__mockforge/api/route-chaos: per-route status overrides.

Those are documented in the book’s chaos chapter; they’re intentionally separate knobs from request-body conformance.

Interpreting bucket totals

Negatives [security]: 739 caught / 1812 missed  ⚠

A negative is a deliberately-bad request that should draw a 4xx from the target (the service you are benching), not from MockForge. The two buckets are about the target’s behaviour:

  • caught = the target rejected it with a 4xx (its validation held).
  • missed = the target accepted it (2xx-3xx) or crashed (5xx) when the probe expected a rejection.

A category that’s all-missed is often the spec telling you that whole validator class isn’t enforced. A category that’s all-caught with no missed is the server doing its job. The interesting reads are partial-misses (some routes enforce, others don’t) — those are usually middleware ordering bugs.

A high “missed” is not automatically a bug

Many probes are spec-valid by construction, so the contract itself permits them and a correct target is right to accept them (counted as “missed” only because the probe hoped for a rejection). Examples:

  • a string field accepts any string, so an owasp:sqli payload like ' OR '1'='1 satisfies the schema — only an app-layer WAF, not the contract, would reject it;
  • an optional query parameter can be dropped (parameters:missing-query);
  • an unconstrained {id} path segment accepts any value (parameters:bad-path-param).

These land in conformance-request-violations.json as typed parameter_negative_probe (or equivalent) rows with a note explaining why they are not a schema breach and that rejecting them is the target’s responsibility. So when parameters or owasp shows 0 caught / N missed, read it as “the contract permits these, and the target chose to accept them” — check the per-probe rows to see which are genuinely unenforced validations versus spec-permitted inputs. The same summary is printed inline under each Negatives [...] line so you don’t have to come back to this page.

Definite issues

Because “missed” needs interpretation, the self-test also prints a Definite issues (N) section and writes a conformance-definite-issues.json sidecar containing ONLY the unambiguous problems, so you can triage many APIs by reading one short list:

  • valid_request_rejected — the target refused a spec-valid (positive) request. It broke a legitimate call; this is always a real problem.
  • server_error — a probe (positive or negative) drew a 5xx. Even a deliberately-bad request should get a clean 4xx, never a crash.

Spec-valid “missed” negatives are deliberately excluded from this view: those are the ones the caught/missed rollup exists to help you judge. A “caught” 4xx is never listed here — a caught negative means the target did its job (rejected a bad request), so it is not a violation even if that exact error status isn’t enumerated in the spec (use --validate-response-schemas if you want to check error bodies against the spec separately).

HTML drill-down cap

The “Missed negatives” table in conformance-report.html caps at 200 rows by default to keep the HTML file viewable on huge specs. Override with --report-missed-cap N (0 = no cap, show everything). The JSON report always carries the full set regardless of the cap.

CLI summary

mockforge bench \
  --conformance --conformance-self-test \
  --spec your-api.yaml \
  --target https://your-api.example.com/ \
  --base-path /api \
  --conformance-header "Authorization: Bearer real-token" \
  --report-missed-cap 0

Output artefacts in bench-results/:

  • conformance-self-test.json — full machine-readable report
  • conformance-report.html — human-readable summary (this page’s labels)
  • conformance-spec-audit.json — pure spec audit (when --spec is set)

See also the conformance overview for the high-level mode docs.

Bench Custom Checks: File Uploads + Cookie/CSRF Chains

mockforge bench --conformance --conformance-custom <yaml> runs a YAML-defined sequence of HTTP probes against a target. Round 38 of issue #79 extends the YAML with three pieces that map directly to common load-test scenarios:

  1. File uploads as multipart/form-data (single or multi-file).
  2. Cookie + CSRF capture and reuse across subsequent requests, with support for parallel and sequential repetition.
  3. Whole-chain iteration so a login + work + logout sequence can be exercised N times under load.

This page is the reference for the YAML knobs. The bench tool ships single-shot custom checks since v0.3.55; the chain features below are purely additive (existing YAML files keep working).

File uploads (multipart/form-data)

The simplest case: send a .json payload as a multipart form field.

custom_checks:
  - name: "custom:upload-json"
    method: POST
    path: /api/uploads
    expected_status: 201
    upload:
      path: /path/to/payload.json
      content_type: application/json
      field_name: file

The bench reads path off disk at request time, builds a multipart/form-data body, and sets the part’s Content-Type to the value you supplied. field_name is the form key the receiving server sees; filename defaults to the basename of path but can be overridden.

Multi-file uploads

uploads: (plural) takes a list. Each file becomes its own part in the same multipart request.

custom_checks:
  - name: "custom:upload-evidence-bundle"
    method: POST
    path: /api/cases/{caseId}/evidence
    expected_status: 201
    uploads:
      - path: /var/cases/photo.jpg
        content_type: image/jpeg
        field_name: photo
      - path: /var/cases/report.docx
        content_type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
        field_name: report
      - path: /var/cases/manifest.xml
        content_type: application/xml
        field_name: manifest
      - path: /var/cases/binary.exe
        content_type: application/octet-stream
        field_name: artifact

Notes:

  • body: (the JSON-string body knob) wins over upload / uploads when both are set. The bench warns on stderr so the mistake is visible.
  • A missing file is logged to stderr but does NOT abort the run; the remaining parts still go out.
  • For very large uploads (hundreds of MiB), --export-requests will write a brief summary like <2 file(s): photo.jpg (image/jpeg, 1234 bytes), report.docx (..., 56 bytes)> instead of dumping bytes into the JSON capture.

The bench supports a chain context: capture values from one response, substitute them into the next request. Three substitution token shapes:

TokenSourceSet by extract:
${var:NAME}a variableheaders: or body_fields:
${cookie:NAME}a Set-Cookie valuecookies:
${header:NAME}alias for ${var:NAME}headers: (reads better when the source was a header)

Unknown tokens are preserved verbatim (e.g. ${var:nope} stays in the request), so a missing capture is visible in the request log rather than silently sending an empty string.

Srikanth’s Sequence 1: login + 16 parallel writes

chain_iterations: 1

custom_checks:
  - name: "custom:login"
    method: POST
    path: /api/login
    expected_status: 200
    body: '{"user":"alice","password":"hunter2"}'
    extract:
      cookies:
        - session
      headers:
        csrf: X-CSRF-Token
      body_fields:
        user_id: data.id

  - name: "custom:do-work"
    method: POST
    path: /api/items
    expected_status: 201
    headers:
      Cookie: "session=${cookie:session}"
      X-CSRF-Token: "${var:csrf}"
    body: '{"action":"create","owner_id":"${var:user_id}"}'
    repeat:
      count: 16
      mode: parallel

The login request captures session (cookie), csrf (header), and user_id (JSON body field at data.id). The follow-up custom:do-work fires 16 concurrent requests, all carrying the same captured values.

Srikanth’s Sequence 2: login + sequential writes

Same shape, but mode: sequential (the default) fires the repeats one after another:

custom_checks:
  - name: "custom:login"
    method: POST
    path: /api/login
    expected_status: 200
    body: '{"user":"alice","password":"hunter2"}'
    extract:
      cookies: [session]
      headers:
        csrf: X-CSRF-Token

  - name: "custom:do-work"
    method: POST
    path: /api/items
    expected_status: 201
    headers:
      Cookie: "session=${cookie:session}"
      X-CSRF-Token: "${var:csrf}"
    body: '{"action":"create"}'
    repeat:
      count: 8
      mode: sequential

Repeat both scenarios N times

chain_iterations: N runs the whole custom_checks list N times. Each iteration starts with a fresh chain context, so a stale session from iteration K can’t accidentally leak into K+1.

chain_iterations: 50

custom_checks:
  - name: "custom:login"
    ...
  - name: "custom:do-work-parallel"
    ...
    repeat:
      count: 16
      mode: parallel
  - name: "custom:do-work-sequential"
    ...
    repeat:
      count: 8
      mode: sequential
  - name: "custom:logout"
    method: POST
    path: /api/logout
    expected_status: 204
    headers:
      Cookie: "session=${cookie:session}"

That YAML defines the exact loop Srikanth asked for in round 38: log in, do 16 parallel writes, do 8 sequential writes, log out, repeat 50 times.

Substitution: where it applies

  • path: template (e.g. /users/${var:user_id}).
  • Every header value.
  • Raw / JSON / form-urlencoded bodies. JSON bodies are walked and only string leaves are touched, so numbers / booleans / arrays are passed through unchanged.
  • Multipart bodies are NOT substituted (binary uploads should stay byte-identical across iterations).

Extraction sources

  • Cookies: extract.cookies is a list of cookie names. The bench walks the response’s Set-Cookie header (multi-cookie headers are comma-split) and captures the matching name=value pair. Attributes after the value (; Path=/; HttpOnly) are dropped.
  • Headers: extract.headers is a map of var_name -> header_name. Header name lookup is case-insensitive on read.
  • Body fields: extract.body_fields is a map of var_name -> dotted_path. The path is a simple object walk (data.token traverses {"data":{"token":"..."}}); arrays and filter expressions are NOT supported here (use the CRUD-flow extractor for that). Non-string JSON values are stringified (42 becomes "42").

Race semantics

Under mode: parallel with count: N, the chain context’s extract runs against the first response (by input order, not completion order). Captures from the remaining N-1 racing requests are dropped. This keeps subsequent checks deterministic. If you genuinely want to forward a per-repeat value, run them sequential.

Running

mockforge bench \
  --conformance \
  --conformance-custom scenarios/login-and-do-work.yaml \
  --target https://api.example.com/ \
  --output bench-results/

--export-requests dumps every request/response (substituted) to conformance-requests.json so you can grep for what actually went on the wire. Without it, the bench still produces the standard conformance-self-test.json aggregate.

Bench capacity sizing

Issue #79 round 29 — Srikanth’s question after running a single 50-target microsoft-graph.yaml bench from a 10-core / 15 GB client and seeing the VM hang at 5 VUs. This page documents what hardware a single client needs for a given target / RPS / duration / spec combination, and how to estimate it without trial and error.

Quick lookup table

These are rough but conservative defaults. Real workloads vary ±30% depending on spec size, body sizes, network latency. When in doubt, size up; one over-provisioned client is cheaper than a 24-hour run that crashes at hour 18.

TargetsRPS / targetVUsCPU coresRAM (GB)Notes
110522smoke tests
11002044single-target load
5502544small multi-target
101005088typical multi-target soak
251001001616medium fleet
501002003232Srikanth’s vCenter sizing
1001004006464large fleet — consider sharding
10050010009696shard into 2+ clients

If your hardware is below the recommended row, expect the bench to queue requests, fall behind RPS, exhaust memory, and eventually hang the OS scheduler. Sharding across multiple client machines (each running a subset of --targets-file) is the right answer past ~50 concurrent targets.

Tooling requirements

Surfaced in #79 round 34: mockforge bench --use-k6 failed on k6 v0.49.0 (Jan 2024) and worked after upgrading. The bench depends on constant-arrival-rate executor semantics and JSON-summary keys that stabilised in k6 1.x.

ToolMinimumNotes
k6>= 1.0.0required for --use-k6; recommended: latest stable
Rust>= 1.74MSRV for cargo install mockforge-cli (aws-lc-rs)
C/C++ compilercc + C++17aws-lc-rs and the vendored OpenSSL build (apt install build-essential cmake)
protocnot neededbundled via protoc-bin-vendored since round 32 (#828)
Build RAM~4 GB minimumsmaller VMs: RUSTFLAGS="-C codegen-units=16" CARGO_BUILD_JOBS=1 or add swap

mockforge bench --use-k6 parses k6 version before launching and warns when it detects a version below 1.0.0.

How to compute it yourself

The bench uses k6 under the hood; the same back-of-envelope k6 sizing math applies, with two MockForge-specific additions:

VU count

VUs ≈ target_count × ceil(RPS_per_target / 10) for steady-state load.

Each k6 VU can sustain ~10-20 RPS comfortably on a modern CPU. Going above 20 RPS per VU eats into the request budget and pushes percentile latencies up. For burst loads, multiply by 1.5.

For your case (50 targets × 100 RPS): 50 × 10 = 500 VUs peak, ~200 VUs sustained.

RAM

RAM_GB ≈ ceil(VUs × 50 MB / 1024) + ceil(target_count × spec_size_mb × 2 / 1024) + ceil(target_count × 0.5)

  • VUs × 50 MB: k6’s per-VU baseline (JS runtime + isolate + per-connection pool).
  • target_count × spec_size_mb × 2: each k6 process keeps the rendered script + spec metadata in memory; doubled for safety. A 10 MB microsoft-graph.yaml renders to ~25 MB of script per target.
  • target_count × 0.5 GB: per-target HTTP connection pool + capture-bound response buffers (16 KiB body cap × concurrent VU fan-out).

For your case (50 targets, 200 VUs, ~10 MB spec):

200 × 50 MB     = 10 GB    (VU baseline)
50 × 10 × 2 / 1024 ≈ 1 GB  (script + spec)
50 × 0.5        = 25 GB    (connection pool + buffers)
                ----
TOTAL           ≈ 36 GB

You had 15 GB. That’s why the VM hung at 5 VUs against 50 targets under a 10 MB spec; each k6 process was OOM’ing trying to load the script. Either provision a 64 GB box, or shard the targets across 2-3 smaller clients.

CPU cores

cores ≈ ceil((VUs × concurrent_requests_per_VU) / 50)

k6 needs about 1 core per 50 in-flight HTTP requests. With keep-alive on (the default), one VU usually has 1 in-flight request at any moment, so cores ≈ VUs / 50 is the right approximation. Bumping --rps above ~10 per VU pushes that ratio up.

For your case: 200 VUs ÷ 50 = 4 cores minimum, but headroom for the OS + script compilation + admin endpoint serving pushes the comfortable number to ~32 on a single client.

When the bench is sized wrong

Symptoms of under-provisioning:

  • VM hangs partway through the run (RAM exhausted, OOM-killer fires).
  • k6 reports http_req_duration p(95) > 30s with target servers responding fast — the bottleneck is the client, not the targets.
  • mockforge bench exits with Cannot allocate memory on body capture.

Symptoms of over-provisioning: none worth worrying about. Extra CPU/RAM costs are tiny compared to the cost of a failed run.

--discard-response-bodies for long load runs

Plain load runs only check status codes and latency, but k6 still buffers every response body in memory by default. On a long, high-VU or many-target run this accumulates until the kernel OOM-killer sends k6 signal: 9 (SIGKILL). Pass --discard-response-bodies so k6 runs with K6_DISCARD_RESPONSE_BODIES=true and drops the bodies it never inspects:

mockforge bench --spec api.yaml --target https://api.example.com \
  --duration 1h --vus 50 --discard-response-bodies

Notes:

  • Multi-target load (--targets-file) already discards bodies by default; the flag additionally covers single-target load runs.
  • It has no effect on conformance / self-test / CRUD-extraction runs, which need the response body to validate or extract fields.
  • If OOM persists on a very large fan-out, also lower --max-concurrency (each target is a separate k6 process) and shorten --duration / --vus.

Sharding past 50 targets

For 50+ targets at 100+ RPS, split the work across N clients:

# split 100 targets into 4 shards of 25 each
jq '.[:25]' all-targets.json > shard1.json
jq '.[25:50]' all-targets.json > shard2.json
jq '.[50:75]' all-targets.json > shard3.json
jq '.[75:]'  all-targets.json > shard4.json

# run each on a separate client
ssh client1 mockforge bench --targets-file shard1.json ...
ssh client2 mockforge bench --targets-file shard2.json ...
ssh client3 mockforge bench --targets-file shard3.json ...
ssh client4 mockforge bench --targets-file shard4.json ...

Then aggregate the per-shard JSONL captures with jq afterwards.

The --conformance-self-test-capture knob

The capture file (conformance-self-test-requests.jsonl) is bounded upstream at 16 KiB per request/response body. For a 100k-probe run that’s ~3 GB on disk. Plan disk space accordingly; the file goes next to the HTML report under --output.

Agent, LLM, and MCP Traffic (Packet-Level Reference)

This page explains, at the HTTP-packet level, the three interaction patterns an AI agent (Cursor, Claude Code, ChatGPT-style clients, or a custom agent) uses:

  1. Agent → LLM — the agent calls a chat/completions API (OpenAI or Anthropic shaped).
  2. MCP-Agent → MCP-Server — the agent, acting as an MCP client, calls tools over JSON-RPC.
  3. Agent → Agent — one agent calls another agent that exposes an LLM-shaped or tool-shaped endpoint.

Every capture below is real traffic taken against MockForge’s built-in mock endpoints (mockforge serve --llm-mock --mcp-mock), so you can reproduce all of it locally with no API key and no external service. The last section shows how to record true .pcap files for Wireshark.

Set up the endpoints used throughout this page:

mockforge serve --spec examples/openapi-demo.json --http-port 3000 --llm-mock --mcp-mock
  • LLM: POST /v1/chat/completions, GET /v1/models, POST /v1/messages
  • MCP: POST /mcp

1. Agent → LLM

1a. Use cases

  • Chat / code completion (Cursor, Claude Code, Copilot-style clients).
  • Tool-calling / function-calling loops (the model returns a tool_calls block; the agent executes and calls back).
  • Retrieval-augmented generation (the agent stuffs retrieved context into the messages array).
  • Streaming UIs (the model streams tokens back over Server-Sent Events).

1b. OpenAI-shaped request (the wire bytes)

POST /v1/chat/completions. The request is a single JSON object; the important headers are Authorization: Bearer <key>, Content-Type: application/json, and Content-Length.

=> Send header, 181 bytes
POST /v1/chat/completions HTTP/1.1
Host: 127.0.0.1:3000
Authorization: Bearer sk-test
Content-Type: application/json
Content-Length: 62

=> Send body, 62 bytes
{"model":"gpt-4o","messages":[{"role":"user","content":"Hi"}]}

Key request fields: model, messages[] (each {role, content} where role is system | user | assistant | tool), and optionally stream, max_tokens, temperature, tools, tool_choice.

1c. OpenAI-shaped response (non-streaming)

<= Recv header
HTTP/1.1 200 OK
content-type: application/json
content-length: 323

<= Recv body
{
  "id": "chatcmpl-a345353a3984267e",
  "object": "chat.completion",
  "created": 0,
  "model": "gpt-4o",
  "choices": [
    { "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 1, "completion_tokens": 12, "total_tokens": 13 }
}

Token accounting lives in usage; the stop condition is finish_reason (stop | length | tool_calls | content_filter).

1d. OpenAI streaming (Server-Sent Events)

When the request sets "stream": true, the response is Content-Type: text/event-stream and the body is a sequence of data: frames, one per token delta, terminated by data: [DONE]:

data: {"choices":[{"delta":{"role":"assistant"},"index":0,"finish_reason":null}],"object":"chat.completion.chunk", ...}

data: {"choices":[{"delta":{"content":"This"},"index":0,"finish_reason":null}],"object":"chat.completion.chunk", ...}

data: {"choices":[{"delta":{"content":" is"},"index":0,"finish_reason":null}],"object":"chat.completion.chunk", ...}

...

data: {"choices":[{"delta":{},"index":0,"finish_reason":"stop"}],"object":"chat.completion.chunk", ...}

data: [DONE]

Each event is separated by a blank line (\n\n). The first frame carries the role, subsequent frames carry content deltas, the penultimate frame carries finish_reason, and the stream closes with the literal [DONE] sentinel.

1e. Anthropic-shaped request/response

Anthropic uses a different path and header scheme: POST /v1/messages, x-api-key: <key>, and anthropic-version: 2023-06-01. max_tokens is required.

Request:

POST /v1/messages HTTP/1.1
x-api-key: sk-ant-test
anthropic-version: 2023-06-01
content-type: application/json

{"model":"claude-3-5-sonnet","max_tokens":64,"messages":[{"role":"user","content":"Hi"}]}

Response:

HTTP/1.1 200 OK
content-type: application/json
content-length: 296

{
  "id": "msg_a345353a3984267e",
  "type": "message",
  "role": "assistant",
  "model": "claude-3-5-sonnet",
  "content": [ { "type": "text", "text": "..." } ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": { "input_tokens": 1, "output_tokens": 12 }
}

Differences from OpenAI worth noting at the packet level: content is an array of typed blocks (not a bare string), usage is input_tokens/output_tokens, and the stop field is stop_reason (end_turn | max_tokens | stop_sequence | tool_use). Anthropic streaming uses named SSE events (message_start, content_block_delta, message_stop) rather than OpenAI’s anonymous data: chunks.


2. MCP-Agent → MCP-Server

2a. Use cases

The Model Context Protocol lets an agent (the MCP client) discover and call tools/resources/prompts exposed by an MCP server. Cursor and Claude Code are MCP clients; the servers they talk to expose things like filesystem access, a database, or a web search. Transport is JSON-RPC 2.0, over stdio (local subprocess) or streamable HTTP (POST /mcp).

2b. Handshake: initialize

The client’s first call negotiates protocol version and advertises its identity:

POST /mcp HTTP/1.1
content-type: application/json

{"jsonrpc":"2.0","id":1,"method":"initialize",
 "params":{"protocolVersion":"2024-11-05","capabilities":{},
           "clientInfo":{"name":"claude-code","version":"1.0"}}}

Response — the server returns its capabilities and identity:

{"jsonrpc":"2.0","id":1,"result":{
  "protocolVersion":"2024-11-05",
  "capabilities":{"tools":{"listChanged":false},
                  "resources":{"listChanged":false},
                  "prompts":{"listChanged":false}},
  "serverInfo":{"name":"mockforge-mcp","version":"..."}}}

After initialize the client sends a notifications/initialized notification (a JSON-RPC message with a method but no id, so the server must not reply with a result — MockForge answers 202 Accepted with an empty body).

2c. Discovery and invocation

  • tools/list → { "tools": [ { "name", "description", "inputSchema" } ] }
  • tools/call with { "name", "arguments" }:
POST /mcp HTTP/1.1
content-type: application/json

{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"echo","arguments":{"text":"hello"}}}

Response:

{"jsonrpc":"2.0","id":2,"result":{
  "content":[{"type":"text","text":"hello"}],
  "isError":false}}

resources/list and prompts/list follow the same request/response envelope. A failed tool call still returns HTTP 200 with "isError": true inside result.content; a malformed/unknown method returns a JSON-RPC error object ({"code": -32601, "message": "method not found"}).


3. Agent → Agent

“Agent to agent” traffic is, at the packet level, one of the two patterns above: the callee agent exposes either an LLM-shaped endpoint (so the caller talks to it exactly like section 1) or an MCP/tool endpoint (section 2). Emerging A2A protocols layer a task/session envelope on top, but the transport is still HTTP + JSON (often JSON-RPC), so the capture technique is identical.

To simulate a fan-out of many agents against one target, point MockForge’s k6 load generator at the mock endpoint:

mockforge bench --spec examples/openapi-demo.json --target http://localhost:3000 \
  --scenario spike --vus 200

MockForge can also sit in front of a real model as a recording proxy so you can capture and replay real traffic deterministically — see --llm-mock-mode record|replay|proxy.


4. Capturing real PCAP files

The traces above are the HTTP payloads. To get true .pcap files (with TCP/IP framing) for Wireshark:

Plaintext HTTP (MockForge on http://)

# 1. Start the mock endpoints on a plain HTTP port
mockforge serve --spec examples/openapi-demo.json --http-port 3000 --llm-mock --mcp-mock

# 2. Capture loopback traffic on that port to a file
sudo tcpdump -i lo -w agent-llm.pcap 'tcp port 3000'
# (or: tshark -i lo -f 'tcp port 3000' -w agent-llm.pcap)

# 3. In another shell, drive the traffic
curl -N -X POST http://localhost:3000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{"model":"gpt-4o","stream":true,"messages":[{"role":"user","content":"hi"}]}'

curl -X POST http://localhost:3000/mcp -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo","arguments":{"text":"hi"}}}'

# 4. Stop tcpdump (Ctrl-C) and open agent-llm.pcap in Wireshark.
#    Wireshark's "Follow > HTTP Stream" reconstructs each request/response.

Because the port is plaintext HTTP, every byte (request line, headers, JSON body, and each SSE data: frame) is visible in the capture with no decryption.

Real providers over TLS (https://)

Real OpenAI/Anthropic/MCP-over-HTTPS traffic is TLS-encrypted, so a raw pcap shows only ciphertext. Two ways to see the plaintext:

  • SSLKEYLOGFILE — set export SSLKEYLOGFILE=/tmp/keys.log before launching the client, capture with tcpdump, then point Wireshark at the key log (Preferences → Protocols → TLS → (Pre)-Master-Secret log filename) to decrypt.
  • mitmproxy — run mitmproxy (or mitmdump -w flows.mitm) as an explicit proxy and route the agent through it; it shows and records the decrypted request/response for each call.

To capture the exact bytes without a proxy at all, curl --trace-ascii trace.txt dumps every header and body byte sent and received — the same view used to produce the captures on this page.


Quick reference

InteractionMethod + pathAuth headerBody envelopeStreaming
Agent → LLM (OpenAI)POST /v1/chat/completionsAuthorization: Bearer{model, messages[]}SSE data: chunks + [DONE]
Agent → LLM (Anthropic)POST /v1/messagesx-api-key + anthropic-version{model, max_tokens, messages[]}named SSE events
MCP-Agent → MCP-ServerPOST /mcp(transport-defined)JSON-RPC 2.0 {jsonrpc, id, method, params}notifications have no id

Troubleshooting

This guide helps you diagnose and resolve common issues with MockForge. If you’re experiencing problems, follow the steps below to identify and fix the issue.

Quick Diagnosis

Check Server Status

First, verify that MockForge is running and accessible:

# Check if processes are running
ps aux | grep mockforge

# Check listening ports
netstat -tlnp | grep -E ":(3000|3001|50051|9080)"

# Test basic connectivity
curl -I http://localhost:3000/health 2>/dev/null || echo "HTTP server not responding"
curl -I http://localhost:9080/health 2>/dev/null || echo "Admin UI not responding"

Check Logs

Enable verbose logging to see detailed information:

# Run with debug logging
RUST_LOG=mockforge=debug mockforge serve --spec api-spec.yaml

# View recent logs
tail -f mockforge.log

# Filter logs by component
grep "ERROR" mockforge.log
grep "WARN" mockforge.log

HTTP API Issues

Server Won’t Start

Symptoms: mockforge serve exits immediately with error

Common causes and solutions:

  1. Port already in use:

    # Find what's using the port
    lsof -i :3000
    
    # Kill conflicting process
    kill -9 <PID>
    
    # Or use different port
    mockforge serve --http-port 3001
    
  2. Invalid OpenAPI specification:

    # Validate YAML syntax
    yamllint api-spec.yaml
    
    # Validate OpenAPI structure
    swagger-cli validate api-spec.yaml
    
    # Test with minimal spec
    mockforge serve --spec examples/openapi-demo.json
    
  3. File permissions:

    # Check file access
    ls -la api-spec.yaml
    
    # Fix permissions if needed
    chmod 644 api-spec.yaml
    

404 Errors for Valid Routes

Symptoms: API returns 404 for endpoints that should exist

Possible causes:

  1. OpenAPI spec not loaded correctly:

    # Check if spec was loaded
    grep "OpenAPI spec loaded" mockforge.log
    
    # Verify file path
    ls -la api-spec.yaml
    
  2. Path matching issues:

    • Ensure paths in spec match request URLs
    • Check for trailing slashes
    • Verify HTTP methods match
  3. Template expansion disabled:

    # Enable template expansion
    MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.yaml
    

Template Variables Not Working

Symptoms: {{variable}} appears literally in responses

Solutions:

  1. Enable template expansion:

    # Via environment variable
    MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api-spec.yaml
    
    # Via config file
    printf "http:\n  response_template_expand: true\n" > config.yaml
    mockforge serve --config config.yaml --spec api-spec.yaml
    
  2. Check template syntax:

    • Use {{variable}} not ${variable}
    • Ensure variables are defined in spec examples
    • Check for typos in variable names

Validation Errors

Symptoms: Requests return 400/422 with validation errors

Solutions:

  1. Adjust validation mode:

    # Disable validation
    MOCKFORGE_REQUEST_VALIDATION=off mockforge serve --spec api-spec.yaml
    
    # Use warning mode
    MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api-spec.yaml
    
  2. Fix request format:

    • Ensure Content-Type header matches request body format
    • Verify required fields are present
    • Check parameter formats match OpenAPI spec

WebSocket Issues

Connection Fails

Symptoms: WebSocket client cannot connect

Common causes:

  1. Wrong port or path:

    # Check WebSocket port
    netstat -tlnp | grep :3001
    
    # Test connection
    websocat ws://localhost:3001/ws
    
  2. Replay file not found:

    # Check file exists
    ls -la ws-replay.jsonl
    
    # Run without replay file
    mockforge serve --ws-port 3001  # No replay file specified
    

Messages Not Received

Symptoms: WebSocket connection established but no messages

Solutions:

  1. Check replay file format:

    # Validate JSONL syntax
    node -e "
    const fs = require('fs');
    const lines = fs.readFileSync('ws-replay.jsonl', 'utf8').split('\n');
    lines.forEach((line, i) => {
      if (line.trim()) {
        try { JSON.parse(line); }
        catch (e) { console.log(\`Line \${i+1}: \${e.message}\`); }
      }
    });
    "
    
  2. Verify message timing:

    • Check ts values are in milliseconds
    • Ensure messages have required fields (ts, dir, text)

Interactive Mode Issues

Symptoms: Client messages not triggering responses

Debug steps:

  1. Check regex patterns:

    # Test regex patterns
    node -e "
    const pattern = '^HELLO';
    const test = 'HELLO world';
    console.log('Match:', test.match(new RegExp(pattern)));
    "
    
  2. Verify state management:

    • Check that state variables are properly set
    • Ensure conditional logic is correct

gRPC Issues

Service Not Found

Symptoms: grpcurl list shows no services

Solutions:

  1. Check proto directory:

    # Verify proto files exist
    find proto/ -name "*.proto"
    
    # Check directory path
    MOCKFORGE_PROTO_DIR=proto/ mockforge serve --grpc-port 50051
    
  2. Compilation errors:

    # Check for proto compilation errors
    cargo build --verbose 2>&1 | grep -i proto
    
  3. Reflection disabled:

    # Enable gRPC reflection
    MOCKFORGE_GRPC_REFLECTION_ENABLED=true mockforge serve --grpc-port 50051
    

Method Calls Fail

Symptoms: gRPC calls return errors

Debug steps:

  1. Check service definition:

    # List service methods
    grpcurl -plaintext localhost:50051 describe mockforge.user.UserService
    
  2. Validate request format:

    # Test with verbose output
    grpcurl -plaintext -v -d '{"user_id": "123"}' localhost:50051 mockforge.user.UserService/GetUser
    
  3. Check proto compatibility:

    • Ensure client and server use same proto definitions
    • Verify message field names and types match

Admin UI Issues

UI Not Loading

Symptoms: Browser shows connection error

Solutions:

  1. Check admin port:

    # Verify port is listening
    curl -I http://localhost:9080 2>/dev/null || echo "Admin UI not accessible"
    
    # Try different port
    mockforge serve --admin --admin-port 9090
    
  2. CORS issues:

    • Admin UI should work from any origin by default
    • Check browser console for CORS errors
  3. Run the Admin UI on its own:

    # Start only the Admin UI (standalone server)
    mockforge admin
    

API Endpoints Not Working

Symptoms: UI loads but API calls fail

Solutions:

  1. Check admin API:

    # Test admin API directly
    curl http://localhost:9080/__mockforge/status
    
  2. Enable admin API:

    # Ensure admin API is not disabled
    mockforge serve --admin  # Don't use --disable-admin-api
    

Configuration Issues

Config File Not Loading

Symptoms: Settings from config file are ignored

Solutions:

  1. Validate YAML syntax:

    # Check YAML format
    python3 -c "import yaml; yaml.safe_load(open('config.yaml'))"
    
    # Or use yamllint
    yamllint config.yaml
    
  2. Check file path:

    # Use absolute path
    mockforge serve --config /full/path/to/config.yaml
    
    # Verify file permissions
    ls -la config.yaml
    
  3. Environment variable override:

    • Remember that environment variables override config file settings
    • Command-line arguments override both

Environment Variables Not Working

Symptoms: Environment variables are ignored

Common issues:

  1. Shell not reloaded:

    # Export variable and reload shell
    export MOCKFORGE_HTTP_PORT=3001
    exec $SHELL
    
  2. Variable name typos:

    # Check variable is set
    echo $MOCKFORGE_HTTP_PORT
    
    # List all MockForge variables
    env | grep MOCKFORGE
    

Performance Issues

High Memory Usage

Symptoms: MockForge consumes excessive memory

Solutions:

  1. Reduce concurrent connections:
    # Limit connection pool
    # config: core.max_connections; or use --max-connections at boot
    

mockforge serve


2. **Disable unnecessary features**:
```bash
# Run with minimal features
MOCKFORGE_REQUEST_VALIDATION=off MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=false mockforge serve
  1. Monitor resource usage:
    # Check memory usage
    ps aux | grep mockforge
    
    # Monitor over time
    htop -p $(pgrep mockforge)
    

Slow Response Times

Symptoms: API responses are slow

Debug steps:

  1. Enable latency logging:

    RUST_LOG=mockforge=debug mockforge serve --spec api-spec.yaml 2>&1 | grep -i latency
    
  2. Check template complexity:

    • Complex templates can slow response generation
    • Consider caching for frequently used templates
  3. Profile performance:

    # Use cargo flamegraph for profiling
    cargo flamegraph --bin mockforge-cli -- serve --spec api-spec.yaml
    

Docker Issues

Container Won’t Start

Symptoms: Docker container exits immediately

Solutions:

  1. Check container logs:

    docker logs <container-id>
    
    # Run with verbose output
    docker run --rm mockforge mockforge serve --spec api-spec.yaml
    
  2. Volume mounting issues:

    # Ensure spec file is accessible
    docker run -v $(pwd)/api-spec.yaml:/app/api-spec.yaml \
      mockforge mockforge serve --spec /app/api-spec.yaml
    
  3. Port conflicts:

    # Use different ports
    docker run -p 3001:3000 -p 3002:3001 mockforge
    

Port Already in Use

Symptoms: Container fails to start with “address already in use” error

Solutions:

# Check what's using the ports
netstat -tlnp | grep :3000
# Or on macOS:
lsof -i :3000

# Use different ports
docker run -p 3001:3000 -p 3002:3001 mockforge

# Or in docker-compose.yml
services:
  mockforge:
    ports:
      - "3001:3000"  # Map host 3001 to container 3000
      - "3002:3001"  # Map host 3002 to container 3001

Permission Issues

Symptoms: Container can’t read/write mounted volumes

Solutions:

# Fix volume permissions (Linux)
sudo chown -R 1000:1000 fixtures/
sudo chown -R 1000:1000 logs/

# Or run container as your user
docker run --user $(id -u):$(id -g) \
  -v $(pwd)/fixtures:/app/fixtures \
  mockforge

# macOS typically doesn't need permission fixes

Build Issues

Symptoms: Docker build fails or takes too long

Solutions:

# Clear Docker cache
docker system prune -a

# Rebuild without cache
docker build --no-cache -t mockforge .

# Check disk space
df -h

# Remove unused images
docker image prune -a

Container Performance Issues

Symptoms: Slow response times in Docker

Solutions:

  1. Increase resources (Docker Desktop):

    • Settings → Resources → Memory: Increase to 4GB+
    • Settings → Resources → CPUs: Increase to 2+
  2. Reduce logging verbosity:

    docker run -e RUST_LOG=info mockforge
    # Instead of RUST_LOG=debug
    
  3. Use Docker volumes instead of bind mounts for better performance:

    volumes:
      - mockforge-data:/app/data  # Named volume (faster)
      # Instead of:
      # - ./data:/app/data       # Bind mount (slower on macOS/Windows)
    

Networking Issues

Symptoms: Can’t connect to MockForge from other containers

Solutions:

# Use Docker network
docker network create mockforge-net

docker run --network mockforge-net --name mockforge \
  -p 3000:3000 mockforge

# Other containers on same network can access via:
# http://mockforge:3000

In docker-compose.yml:

services:
  mockforge:
    networks:
      - app-network

  frontend:
    environment:
      API_URL: http://mockforge:3000
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Getting Help

Log Analysis

# Extract error patterns
grep "ERROR" mockforge.log | head -10

# Find recent issues
tail -100 mockforge.log | grep -E "(ERROR|WARN)"

# Count error types
grep "ERROR" mockforge.log | sed 's/.*ERROR //' | sort | uniq -c | sort -nr

Debug Commands

# Full system information
echo "=== System Info ==="
uname -a
echo "=== Rust Version ==="
rustc --version
echo "=== Cargo Version ==="
cargo --version
echo "=== Running Processes ==="
ps aux | grep mockforge
echo "=== Listening Ports ==="
netstat -tlnp | grep -E ":(3000|3001|50051|9080)"
echo "=== Disk Space ==="
df -h
echo "=== Memory Usage ==="
free -h

Community Support

If you can’t resolve the issue:

  1. Check existing issues: Search GitHub issues for similar problems
  2. Create a minimal reproduction: Isolate the issue with minimal configuration
  3. Include debug information: Attach logs, configuration, and system details
  4. Use descriptive titles: Clearly describe the problem in issue titles

Emergency Stop

If MockForge is causing issues:

# Kill all MockForge processes
pkill -f mockforge

# Kill specific process
kill -9 <mockforge-pid>

# Clean up any leftover files
rm -f mockforge.log

This troubleshooting guide covers the most common issues. For more specific problems, check the logs and consider creating an issue on GitHub with detailed information about your setup and the problem you’re experiencing.

Common Issues & Solutions

This guide addresses the most frequently encountered issues when using MockForge and provides quick solutions.

Server Issues

Port Already in Use

Problem: Error: Address already in use (os error 98)

Solutions:

# Find what's using the port
lsof -i :3000
# On Windows: netstat -ano | findstr :3000

# Kill the process
kill -9 <PID>

# Or use a different port
mockforge serve --spec api.json --http-port 3001

Prevention: Check ports before starting:

# Quick check script
ports=(3000 3001 9080 50051)
for port in "${ports[@]}"; do
  if lsof -i :$port > /dev/null; then
    echo "Port $port is in use"
  fi
end

Server Won’t Start

Problem: MockForge exits immediately or fails silently

Debugging Steps:

  1. Check configuration
# Validate config file
mockforge config validate --config mockforge.yaml
  1. Check logs
# Enable verbose logging
RUST_LOG=debug mockforge serve --spec api.json 2>&1 | tee mockforge.log
  1. Test with minimal config
# Start with just the spec
mockforge serve --spec examples/openapi-demo.json --http-port 3000
  1. Check file permissions
ls -la api.json mockforge.yaml
chmod 644 api.json mockforge.yaml

Template & Data Issues

Template Variables Not Expanding

Problem: {{uuid}} appears literally in responses instead of generating UUIDs

Solutions:

# Enable template expansion via environment variable
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api.json

# Or via config file
# mockforge.yaml
http:
  response_template_expand: true

Common Mistake: Forgetting that template expansion is opt-in for security reasons.

Faker Functions Not Working

Problem: {{faker.name}} not generating fake data

Solutions:

  1. Enable template expansion (see above)
  2. Check faker function name: Use lowercase, e.g., {{faker.name}} not {{Faker.Name}}
  3. Install faker if required: Some advanced faker features may require additional setup

Valid faker functions:

  • {{faker.name}} - Person name
  • {{faker.email}} - Email address
  • {{faker.address}} - Street address
  • {{faker.phone}} - Phone number
  • {{faker.company}} - Company name

See Templating Reference for complete list.

Invalid Date/Timestamp Format

Problem: {{now}} generates invalid date format

Solutions:

# Use proper format in OpenAPI spec
properties:
  createdAt:
    type: string
    format: date-time  # Important!
    example: "{{now}}"

Alternative: Use custom format

{
  "timestamp": "{{now | date:'%Y-%m-%d'}}"
}

OpenAPI Spec Issues

Spec Not Loading

Problem: Error: Failed to parse OpenAPI specification

Solutions:

  1. Validate spec syntax
# Using swagger-cli
swagger-cli validate api.json

# Or online
# https://editor.swagger.io/
  1. Check file format
# JSON
cat api.json | jq .

# YAML
yamllint api.yaml
  1. Check OpenAPI version
{
  "openapi": "3.0.3",  // Not "3.0" or "swagger": "2.0"
  ...
}
  1. Resolve JSON schema references
# Use json-schema-ref-resolver if needed
npm install -g json-schema-ref-resolver
json-schema-ref-resolver api.json > resolved-api.json

404 for Valid Routes

Problem: Endpoints return 404 even though they exist in the spec

Debugging:

  1. Check path matching
# Verify paths don't have trailing slashes mismatch
# Spec: /users (should match request: GET /users)
curl http://localhost:3000/users  # ✅
curl http://localhost:3000/users/ # ❌ May not match
  1. Check HTTP method
# Ensure method matches spec
# Spec defines GET but you're using POST
curl -X GET http://localhost:3000/users  # ✅
curl -X POST http://localhost:3000/users # ❌ May not match
  1. Enable debug logging
RUST_LOG=mockforge_http=debug mockforge serve --spec api.json

CORS Issues

CORS Errors in Browser

Problem: Access to fetch at 'http://localhost:3000/users' from origin 'http://localhost:3001' has been blocked by CORS policy

Solutions:

# mockforge.yaml
http:
  cors:
    enabled: true
    allowed_origins:
      - "http://localhost:3000"
      - "http://localhost:3001"
      - "http://localhost:5173"  # Vite default
    allowed_methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
    allowed_headers: ["Content-Type", "Authorization"]

CORS is YAML-only; configure under http.cors.* in mockforge.yaml (no env-var equivalents in v0.3.x).

Debugging: Check browser console for exact CORS error message - it will tell you which header is missing.

Validation Issues

Valid Requests Getting Rejected

Problem: Requests return 422/400 even though they look correct

Solutions:

  1. Check validation mode
# Use 'warn' instead of 'enforce' for development
MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api.json
  1. Check Content-Type header
# Ensure Content-Type matches spec
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John"}'
  1. Check required fields
# Spec may require fields you're not sending
# Check spec for 'required' array
  1. Validate request body structure
# Use Admin UI to see exact request received
# Visit http://localhost:9080 to inspect requests

Validation Too Strict

Problem: Validation rejects requests that should be valid

Solutions:

  1. Temporarily disable validation
MOCKFORGE_REQUEST_VALIDATION=off mockforge serve --spec api.json
  1. Fix spec if it’s incorrect
// Spec might mark optional fields as required
"properties": {
  "name": { "type": "string" },
  "email": { "type": "string" }
},
"required": []  // Empty array = all optional

WebSocket Issues

Connection Refused

Problem: WebSocket connection fails immediately

Solutions:

  1. Check WebSocket port
# Verify port is open
netstat -tlnp | grep :3001
  1. Check replay file exists
# Ensure file path is correct
ls -la ws-replay.jsonl
MOCKFORGE_WS_REPLAY_FILE=./ws-replay.jsonl mockforge serve --ws-port 3001
  1. Check WebSocket enabled
# Ensure WebSocket server is started
mockforge serve --ws-port 3001  # Explicit port needed

Messages Not Received

Problem: WebSocket connects but no messages arrive

Solutions:

  1. Check replay file format
# Validate JSONL syntax
cat ws-replay.jsonl | jq -r '.'  # Should parse each line as JSON
  1. Check message timing
// Replay file format
{"ts": 0, "dir": "out", "text": "Welcome"}
{"ts": 1000, "dir": "out", "text": "Next message"}
  1. Check waitFor patterns
// Ensure regex patterns match
{"waitFor": "^CLIENT_READY$", "text": "Acknowledged"}

Configuration Issues

Config File Not Found

Problem: Error: Configuration file not found

Solutions:

  1. Use absolute path
mockforge serve --config /full/path/to/mockforge.yaml
  1. Check file name
# Valid names
mockforge.yaml
mockforge.yml
.mockforge.yaml
.mockforge.yml
mockforge.config.ts
mockforge.config.js
  1. Check current directory
pwd
ls -la mockforge.yaml

Environment Variables Not Applied

Problem: Environment variables seem to be ignored

Solutions:

  1. Check variable names: every recognized env var starts with the prefix MOCKFORGE_ followed by <SECTION>_<OPTION> in upper-case (e.g. MOCKFORGE_HTTP_PORT, not MOCKFORGE_PORT). Run mockforge config list-env-vars for the canonical list of recognized names.

  2. Check shell reload

# Export and verify
export MOCKFORGE_HTTP_PORT=3000
echo $MOCKFORGE_HTTP_PORT  # Should show 3000

# Or use inline
MOCKFORGE_HTTP_PORT=3000 mockforge serve --spec api.json
  1. Check precedence
# CLI flags override env vars
mockforge serve --spec api.json --http-port 3001
# Even if MOCKFORGE_HTTP_PORT=3000, port will be 3001

Performance Issues

Slow Response Times

Problem: API responses are slow

Solutions:

  1. Disable template expansion if not needed
# Template expansion adds overhead
mockforge serve --spec api.json  # No templates = faster
  1. Reduce validation overhead
# Validation adds latency
MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api.json  # Faster than 'enforce'
  1. Check response complexity
# Large responses or complex templates slow things down
# Consider simplifying responses for development
  1. Monitor resource usage
# Check CPU/memory
top -p $(pgrep mockforge)

High Memory Usage

Problem: MockForge consumes too much memory

Solutions:

  1. Limit connection pool
# config: core.max_connections; or use --max-connections at boot
mockforge serve --spec api.json
  1. Disable features not needed
# Minimal configuration
MOCKFORGE_REQUEST_VALIDATION=off \
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=false \
  mockforge serve --spec api.json  # admin UI is off unless --admin is passed
  1. Check for memory leaks
# Monitor over time
watch -n 1 'ps aux | grep mockforge | grep -v grep'

Docker Issues

Container Exits Immediately

Problem: Docker container starts then immediately stops

Solutions:

  1. Check logs
docker logs <container-id>
docker logs -f <container-id>  # Follow logs
  1. Run interactively
docker run -it --rm mockforge mockforge serve --spec api.json
  1. Check volume mounts
# Ensure spec file is accessible
docker run -v $(pwd)/api.json:/app/api.json \
  mockforge mockforge serve --spec /app/api.json

Port Mapping Issues

Problem: Can’t access MockForge from host

Solutions:

# Proper port mapping
docker run -p 3000:3000 -p 9080:9080 mockforge

# Verify ports are exposed
docker port <container-id>

Permission Issues

Problem: Can’t read/write mounted volumes

Solutions:

# Fix permissions
sudo chown -R 1000:1000 ./fixtures ./logs

# Or run as specific user
docker run --user $(id -u):$(id -g) \
  -v $(pwd)/fixtures:/app/fixtures \
  mockforge

Admin UI Issues

Admin UI Not Loading

Problem: Can’t access http://localhost:9080

Solutions:

  1. Enable admin UI
mockforge serve --spec api.json --admin --admin-port 9080
  1. Check port
# Verify port is listening
curl http://localhost:9080
netstat -tlnp | grep :9080
  1. Try different port
mockforge serve --spec api.json --admin --admin-port 9090
# Access at http://localhost:9090

Admin API Not Working

Problem: Admin UI loads but API calls fail

Solutions:

# Test admin API directly
curl http://localhost:9080/__mockforge/status

# Enable admin API explicitly
MOCKFORGE_ADMIN_API_ENABLED=true mockforge serve --spec api.json --admin

Plugin Issues

Plugin Won’t Load

Problem: Error: Failed to load plugin

Solutions:

  1. Check plugin format
# Validate WASM file
file plugin.wasm  # Should show: WebAssembly

# Check plugin manifest
mockforge plugin validate plugin.wasm
  1. Check permissions
# Ensure plugin file is readable
chmod 644 plugin.wasm
  1. Check compatibility
# Plugin may be for different MockForge version
mockforge --version
# Check plugin requirements

Plugin Crashes

Problem: Plugin causes MockForge to crash

Solutions:

  1. Check plugin logs
# Re-run plugin validation with debug logging
RUST_LOG=mockforge_plugin_loader=debug mockforge plugin validate ./plugin.wasm
  1. Check resource limits
# plugin.yaml
capabilities:
  resources:
    max_memory_bytes: 67108864  # 64MB
    max_cpu_time_ms: 5000      # 5 seconds

Getting More Help

If none of these solutions work:

  1. Collect debug information
# System info
uname -a
rustc --version
mockforge --version

# Check logs
RUST_LOG=debug mockforge serve --spec api.json 2>&1 | tee debug.log

# Test with minimal config
mockforge serve --spec examples/openapi-demo.json --http-port 3000
  1. Search existing issues

  2. Create minimal reproduction

    • Create smallest possible config that reproduces issue
    • Include OpenAPI spec (if relevant)
    • Include error logs
  3. Open GitHub issue

    • Use descriptive title
    • Include system info, version, logs
    • Attach minimal reproduction

See Also:

Frequently Asked Questions (FAQ)

Quick answers to common questions about MockForge.

General Questions

What is MockForge?

MockForge is a comprehensive multi-protocol mocking framework for APIs. It allows you to create realistic mock servers for HTTP/REST, gRPC, WebSocket, and GraphQL without writing code. Perfect for frontend development, integration testing, and parallel team development.

Is MockForge free?

Yes, MockForge is completely free and open-source under MIT/Apache-2.0 licenses. There are no premium tiers, paid features, or usage limits.

What protocols does MockForge support?

MockForge supports:

  • HTTP/REST: OpenAPI/Swagger-based mocking with full validation
  • gRPC: Dynamic service discovery from .proto files with HTTP Bridge
  • WebSocket: Replay mode, interactive mode, and AI event generation
  • GraphQL: Schema-based mocking with automatic resolver generation

How does MockForge compare to WireMock, Mockoon, or MockServer?

See our detailed comparison table in the README. Key differentiators:

  • Multi-protocol in a single binary
  • AI-powered mock generation and data drift
  • WASM plugin system for extensibility
  • gRPC HTTP Bridge for REST access to gRPC services
  • Built-in encryption for sensitive data
  • Rust performance with native compilation
  • Multi-language SDKs - Native support for 6 languages vs WireMock’s Java-first approach

For detailed ecosystem comparison, see Ecosystem Comparison Guide.

Can I use MockForge in production?

Yes! MockForge is production-ready with:

  • Comprehensive test coverage
  • Security audits
  • Performance benchmarks
  • Docker deployment support
  • Observability (Prometheus metrics, tracing)

However, it’s primarily designed for development and testing. For production API mocking, ensure proper security configurations.


Getting Started

How do I install MockForge?

Three options:

# 1. From crates.io (requires Rust)
cargo install mockforge-cli

# 2. From source
git clone https://github.com/SaaSy-Solutions/mockforge
cd mockforge && make setup && make install

# 3. Using Docker
docker pull ghcr.io/saasy-solutions/mockforge:latest

See the Installation Guide for details.

What’s the fastest way to get started?

Follow our 5-Minute Tutorial:

  1. cargo install mockforge-cli
  2. mockforge init my-project
  3. mockforge serve --config mockforge.yaml
  4. Test with curl

Do I need to know Rust to use MockForge?

No. MockForge is a CLI tool you can use without Rust knowledge. You only need Rust if:

  • Building from source
  • Developing custom plugins
  • Embedding MockForge as a library

What programming languages are supported?

MockForge provides native SDKs for 6 languages:

  • Rust - Native SDK with zero-overhead embedding
  • Node.js/TypeScript - Full TypeScript support
  • Python - Context manager support with type hints
  • Go - Idiomatic Go API
  • Java - Maven/Gradle integration
  • .NET/C# - NuGet package

All SDKs support embedded mock servers in your test suites. See SDK Documentation for examples.

Can I use MockForge from Python/Node.js/Go/etc.?

Yes! MockForge provides native SDKs for multiple languages. You can embed mock servers directly in your test code:

Python:

from mockforge_sdk import MockServer

with MockServer(port=3000) as server:
    server.stub_response('GET', '/api/users/123', {'id': 123})
    # Your test code here

Node.js:

import { MockServer } from '@mockforge-dev/sdk';

const server = await MockServer.start({ port: 3000 });
await server.stubResponse('GET', '/api/users/123', { id: 123 });

Go:

server := mockforge.NewMockServer(mockforge.MockServerConfig{Port: 3000})
server.Start()
defer server.Stop()

See Ecosystem & Use Cases Guide for complete examples in all languages.

How do I create my first mock API?

# 1. Initialize a project
mockforge init my-api

# 2. Edit the generated mockforge.yaml
vim mockforge.yaml

# 3. Start the server
mockforge serve --config mockforge.yaml

# 4. Test it
curl http://localhost:3000/your-endpoint

Or use an existing OpenAPI spec:

mockforge serve --spec your-api.json

Configuration & Setup

How do I configure MockForge?

Three ways (in order of priority):

  1. CLI flags: mockforge serve --http-port 3000
  2. Environment variables: export MOCKFORGE_HTTP_PORT=3000
  3. Config file: mockforge serve --config config.yaml

See the Configuration Guide and Complete Config Template.

Where should I put my configuration file?

MockForge looks for config files in this order:

  1. Path specified with --config
  2. MOCKFORGE_CONFIG_FILE environment variable
  3. ./mockforge.yaml or ./mockforge.yml in current directory
  4. Auto-discovered in parent directories

Can I use environment variables for all settings?

Yes! Every config option can be set via environment variables using the MOCKFORGE_ prefix:

export MOCKFORGE_HTTP_PORT=3000
export MOCKFORGE_ADMIN_ENABLED=true
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

How do I validate my configuration?

mockforge config validate
mockforge config validate --config my-config.yaml

See the Configuration Validation Guide.


Why does my hosted mock return 401 when I change it with curl?

Hosted mocks protect MockForge’s management API. Writes to /__mockforge/* and the other MockForge control routes (creating mocks, chaos, time travel, the recorder) need the deployment’s management token. Open the deployment on the Hosted Mocks page, press Reveal next to Management token, and send it as a header:

curl -X POST https://<your-mock>/__mockforge/api/mocks \
  -H 'X-MockForge-Management-Token: mfm_...' \
  -H 'content-type: application/json' \
  -d '{"id":"hello","method":"GET","path":"/hello","response":{"body":{"hi":true}}}'

Reads (the spec, route list, docs, live stream) and your mocked API itself don’t need the token. Self-hosted mockforge serve doesn’t use one.

OpenAPI & HTTP Mocking

Can I use Swagger/OpenAPI specs?

Yes! Both OpenAPI 3.0 and Swagger 2.0 are supported:

mockforge serve --spec openapi.json
mockforge serve --spec swagger.yaml

MockForge automatically generates mock endpoints from your specification.

How does request validation work?

Three modes:

  • off: No validation (accept all requests)
  • warn: Log validation errors but accept requests
  • enforce: Reject invalid requests with 400/422
MOCKFORGE_REQUEST_VALIDATION=enforce mockforge serve --spec api.json

Why aren’t my template variables working?

Template expansion must be explicitly enabled:

# Via environment
export MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true

# Via config
http:
  response_template_expand: true

This is a security feature to prevent accidental template processing.

What template variables are available?

{{uuid}}          - Random UUID v4
{{now}}           - Current timestamp (ISO 8601)
{{now+2h}}        - Timestamp 2 hours from now
{{now-30m}}       - Timestamp 30 minutes ago
{{randInt 1 100}} - Random integer 1-100
{{rand.float}}    - Random float
{{faker.email}}   - Fake email address
{{faker.name}}    - Fake person name
{{request.body.field}}   - Access request data
{{request.path.id}}      - Path parameters
{{request.header.Auth}}  - Request headers

See the Templating Reference for complete details.

Can I override specific endpoints?

Yes! Define custom routes in your config that override OpenAPI spec:

http:
  openapi_spec: api.json
  routes:
    - path: /custom/endpoint
      method: GET
      response:
        status: 200
        body: '{"custom": "response"}'

gRPC Mocking

Do I need to compile my proto files?

No. MockForge dynamically parses .proto files at runtime. Just:

  1. Put .proto files in ./proto directory
  2. Start MockForge: mockforge serve --grpc-port 50051
  3. Services are automatically discovered and mocked

How do I access gRPC services via HTTP?

Enable the HTTP Bridge:

grpc:
  dynamic:
    enabled: true
    http_bridge:
      enabled: true
      base_path: "/api"

Now access gRPC services as REST APIs:

# gRPC
grpcurl -d '{"id": "123"}' localhost:50051 UserService/GetUser

# HTTP (via bridge)
curl -X POST http://localhost:8080/api/userservice/getuser \
  -d '{"id": "123"}'

Can I use gRPC reflection?

Yes, it’s enabled by default:

# List services
grpcurl -plaintext localhost:50051 list

# Describe a service
grpcurl -plaintext localhost:50051 describe UserService

Does MockForge support gRPC streaming?

Yes, all four streaming modes:

  • Unary (single request → single response)
  • Server streaming (single request → stream of responses)
  • Client streaming (stream of requests → single response)
  • Bidirectional streaming (stream ↔ stream)

WebSocket Mocking

How do I create WebSocket replay files?

Use JSON Lines (JSONL) format:

{"ts":0,"dir":"out","text":"Welcome!","waitFor":"^CLIENT_READY$"}
{"ts":100,"dir":"out","text":"{{uuid}}"}
{"ts":200,"dir":"in","text":"ACK"}
  • ts: Milliseconds timestamp
  • dir: “in” (received) or “out” (sent)
  • text: Message content (supports templates)
  • waitFor: Optional regex/JSONPath pattern

See WebSocket Replay Mode.

Can I match JSON messages?

Yes, use JSONPath in waitFor:

{"waitFor": "$.type", "text": "Matched type field"}
{"waitFor": "$.user.id", "text": "Matched user ID"}

See README-websocket-jsonpath.md.

What’s AI event generation?

Generate realistic WebSocket event streams from narrative descriptions (for example, “Simulate 5 minutes of stock trading”). This is currently exposed as a library API (AiEventGenerator and WebSocketAiConfig in the mockforge-ws crate); there are no mockforge serve flags for it yet.

Perfect for testing real-time features without manually scripting events.


AI Features

Do I need an API key for AI features?

Not necessarily. Three options:

  1. Ollama (Free, Local): No API key needed

    ollama pull llama2
    mockforge serve --ai-enabled --rag-provider ollama
    
  2. OpenAI (Paid): ~$0.01 per 1,000 requests

    export MOCKFORGE_RAG_API_KEY=sk-...
    mockforge serve --ai-enabled --rag-provider openai
    
  3. Anthropic, or OpenAI-compatible APIs: Similar to OpenAI

What are AI features used for?

  • Intelligent Mock Generation: Generate responses from natural language prompts
  • Data Drift Simulation: Realistic data evolution (order status, stock levels, etc.)
  • AI Event Streams: Generate WebSocket event sequences from narratives

See AI_DRIVEN_MOCKING.md.

How much does AI cost?

  • Ollama: Free (runs locally)
  • OpenAI GPT-3.5: ~$0.01 per 1,000 requests
  • OpenAI GPT-4: ~$0.10 per 1,000 requests
  • Anthropic Claude: Similar to GPT-4

Use Ollama for development, OpenAI for production if needed.


Plugins

How do I install plugins?

# From URL
mockforge plugin install https://example.com/plugin.wasm

# From Git with version
mockforge plugin install https://github.com/user/plugin#v1.0.0

# From local file
mockforge plugin install ./my-plugin.wasm

# List installed
mockforge plugin list

Can I create custom plugins?

Yes! Plugins are written in Rust and compiled to WebAssembly:

  1. Use mockforge-plugin-sdk crate
  2. Implement plugin traits
  3. Compile to WASM target
  4. Install and use

See the Plugin Development Guide and Add a Custom Plugin Tutorial.

Are plugins sandboxed?

Yes. Plugins run in a WebAssembly sandbox with:

  • Memory isolation
  • CPU/memory limits
  • No network access (unless explicitly allowed)
  • No file system access (unless explicitly allowed)

See Plugin Security Model.


Admin UI

How do I access the Admin UI?

The Admin UI runs on its own port:

mockforge serve --admin --admin-port 9080
# Access: http://localhost:9080

Use mockforge admin to run the Admin UI as a standalone server without starting the mock servers.

Is authentication available?

Yes. The Admin UI uses JWT login with three roles: Admin (full access), Editor (manage mocks and fixtures), and Viewer (read-only). Mutating admin endpoints are permission-checked per role; read-only GET /__mockforge/* endpoints stay open so the TUI can poll them.

Without JWT_SECRET, MockForge seeds local development users (admin / admin123, editor / editor123, viewer / viewer123). Set JWT_SECRET and MOCKFORGE_DISABLE_DEV_SEED_USERS=true for shared deployments. OAuth/SSO login is not available in the local Admin UI; MockForge Cloud supports OIDC and SAML SSO.

What can I do in the Admin UI?

  • View real-time request logs (via Server-Sent Events)
  • Monitor performance metrics
  • Manage fixtures with drag-and-drop
  • Configure latency and fault injection
  • Search requests and logs
  • View server health and statistics

See Admin UI Walkthrough.


Deployment

Can I run MockForge in Docker?

Yes:

# Using Docker Compose
docker-compose up

# Using Docker directly
docker run -p 3000:3000 -p 9080:9080 mockforge

See DOCKER.md for complete documentation.

How do I deploy to Kubernetes?

Use the Helm chart or create Deployment/Service manifests:

# Using Helm (if available)
helm install mockforge ./charts/mockforge

# Or use kubectl
kubectl apply -f k8s/statefulset.yaml

What ports does MockForge use?

Default ports:

  • 3000: HTTP server
  • 3001: WebSocket server
  • 50051: gRPC server
  • 4000: GraphQL server
  • 9080: Admin UI
  • 9090: Prometheus metrics

All ports are configurable.


Performance & Limits

How many requests can MockForge handle?

Typical performance (modern hardware):

  • HTTP: 10,000+ req/s
  • WebSocket: 1,000+ concurrent connections
  • gRPC: 5,000+ req/s

Performance depends on:

  • Response complexity
  • Template expansion
  • Validation enabled
  • Hardware specs

See our benchmarks.

Does MockForge scale horizontally?

Yes. Run multiple instances behind a load balancer:

# Instance 1
mockforge serve --http-port 3000

# Instance 2
mockforge serve --http-port 3001

# Load balancer distributes traffic

For stateless mocking (no shared state), this works great.

What are the resource requirements?

Minimal:

  • Memory: ~50MB base + ~10MB per 1,000 concurrent connections
  • CPU: 1-2 cores sufficient for most workloads
  • Disk: ~100MB for binary + storage for logs/fixtures

Troubleshooting

Server won’t start - port already in use

# Find what's using the port
lsof -i :3000

# Use a different port
mockforge serve --http-port 3001

Template variables appear literally in responses

Enable template expansion:

MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true mockforge serve --spec api.json

Validation rejecting valid requests

Adjust validation mode:

MOCKFORGE_REQUEST_VALIDATION=warn mockforge serve --spec api.json  # or 'off'

WebSocket connection fails

Check the WebSocket port and replay file:

# Verify port
netstat -tlnp | grep :3001

# Check replay file exists
ls -la ws-replay.jsonl

Admin UI not loading

Verify the admin UI is enabled and port is correct:

mockforge serve --admin --admin-port 9080
curl http://localhost:9080

For more issues, see the Troubleshooting Guide.


Development & Contributing

Can I embed MockForge in my application?

Yes! Use MockForge crates as libraries:

#![allow(unused)]
fn main() {
use mockforge_http::build_router;
use mockforge_core::{ValidationOptions, Config};

let router = build_router(
    Some("api.json".to_string()),
    Some(ValidationOptions::enforce()),
    None,
).await;
}

See the Rust API Documentation.

How do I contribute to MockForge?

  1. Check CONTRIBUTING.md
  2. Look for “good first issue” labels
  3. Fork, make changes, submit PR
  4. Ensure tests pass: cargo test
  5. Follow code style: cargo fmt && cargo clippy

Where can I report bugs?

GitHub Issues

Please include:

  • MockForge version
  • Operating system
  • Configuration file (if applicable)
  • Steps to reproduce
  • Expected vs actual behavior
  • Error logs

Is there a community forum?


Licensing & Commercial Use

What license is MockForge under?

Dual-licensed: MIT OR Apache-2.0

You can choose either license for your use case.

Can I use MockForge commercially?

Yes, absolutely. Both MIT and Apache-2.0 are permissive licenses that allow commercial use without restrictions.

Do I need to open-source my configurations?

No. Your configuration files, mock data, and custom plugins are yours. Only if you modify MockForge source code and distribute it do licensing terms apply.

Can I sell MockForge-based services?

Yes. You can offer:

  • Hosted MockForge instances
  • Custom plugins
  • Support services
  • Training/consulting

Use Cases

What use cases does MockForge support?

MockForge supports a wide range of use cases:

  1. Unit Tests - Embed mock servers directly in test suites across all supported languages
  2. Integration Tests - Test complex multi-service interactions with stateful mocking
  3. Service Virtualization - Replace external dependencies with mocks using proxy mode
  4. Development Environments - Create local development environments without backend dependencies
  5. Isolating from Flaky Dependencies - Simulate network failures and slow responses
  6. Simulating APIs That Don’t Exist Yet - Generate mocks from API specifications before implementation

See Ecosystem & Use Cases Guide for detailed examples and code samples.

Can I use MockForge for unit testing?

Yes! MockForge SDKs allow you to embed mock servers directly in your unit tests:

Rust:

#![allow(unused)]
fn main() {
let mut server = MockServer::new().port(0).start().await?;
server.stub_response("GET", "/api/users/123", json!({"id": 123})).await?;
}

Python:

with MockServer(port=0) as server:
    server.stub_response('GET', '/api/users/123', {'id': 123})

No separate server process required. See SDK Documentation for examples.

How do I replace external APIs in my tests?

Record traffic with the API Flight Recorder, then convert the recordings into replayable fixtures:

# Record interactions into a SQLite database
mockforge serve --spec api.json --recorder --recorder-db ./recordings.db

# Convert recordings into fixtures
mockforge recorder convert --input ./recordings.db --output fixtures/ --format yaml

Or use the SDK to programmatically stub responses. See Service Virtualization for details.

Can I simulate network failures and slow responses?

Yes! MockForge provides built-in latency and fault injection:

# Add latency
mockforge serve --chaos --chaos-latency-ms 500

# Inject failures
mockforge serve --chaos --chaos-http-errors 500,503 --chaos-http-error-probability 0.1

Or configure in your SDK:

const server = await MockServer.start({
  latency: { mode: 'normal', meanMs: 500 },
  failures: { enabled: true, failureRate: 0.1 }
});

See Isolating from Flaky Dependencies for examples.

How do I mock an API that doesn’t exist yet?

Generate mocks from API specifications:

# From OpenAPI spec
mockforge serve --spec api-spec.yaml

# From GraphQL schema
mockforge serve --graphql schema.graphql

# From gRPC proto files (loaded from ./proto in the working directory)
mockforge serve --grpc-port 50051

All endpoints are automatically available with schema-validated responses. See Simulating APIs That Don’t Exist Yet for details.

What’s Next?

Ready to start? Try our 5-Minute Tutorial!

Need more help?

This reference page mirrors the root changelog in CHANGELOG.md so the book and repository stay aligned.

[Unreleased]

[0.3.230] - 2026-10-04

Changed

  • [Cloud] Audit logs no longer record email addresses, usernames or SAML NameIDs. Member, invitation, SSO login and password-reset events identify people by user id or invitation id; failed logins store a keyed hash of the attempted email instead of the address. (#1087)
  • [Cloud] Audit logs are now kept for 400 days and then deleted by a daily retention worker. The append-only trigger allows only this purge, and only for rows past the window; verify_chain treats the oldest surviving row as the chain start. (#1087)
  • [Cloud] Privacy Policy 2.2 and DPA 2.2 describe audit-log retention after account deletion. Terms 2.1 name Delaware as governing law and venue.
  • [DevX] The Kubernetes manifests (k8s/) and the Helm chart now give every MockForge replica its own recorder volume. Previously all replicas mounted one ReadWriteOnce claim holding the recorder’s SQLite database, so pods on other nodes could not start and pods on the same node shared one SQLite file. k8s/deployment.yaml + k8s/pvc.yaml are replaced by k8s/statefulset.yaml (a StatefulSet with a volumeClaimTemplates entry, one recorder-db-mockforge-N claim per pod), and the HPA now targets it. The Helm chart renders a StatefulSet (plus a <fullname>-headless Service) when persistence.enabled is true, the default, and a Deployment without a recorder volume when it is false. Upgrading an existing Helm release replaces its Deployment with a StatefulSet and creates per-pod claims (data-<fullname>-N); the old shared <fullname>-data claim is kept (annotated helm.sh/resource-policy: keep) but no longer mounted, so copy any recordings you need out of it, then delete it. The Kubernetes test workflow’s Chaos Engineering job, which never ran, now runs on manual dispatch and weekly.

Fixed

  • [Reality] bench-chunked sends a valid JSON body when the request’s Content-Type is JSON (application/json or any +json type, from --header or a targets-file headers entry). The body is the spec-generated request body plus a _padding string field, sized to exactly --total-size-bytes and streamed in the same chunks. Previously every body was X filler, so WAFs flagged each request as malformed JSON. Other content types still get filler. (#79)

  • [DevX] Registry audit email hashing compiles under strict unused-qualification lints in both PostgreSQL and SQLite builds. Hashing behavior is unchanged.

  • [Cloud] Flow creation sends the registry-required configuration across all five editors. Federation details have a labeled Back button; portal dialogs, placeholders and disabled controls use readable theme colors and wrapping action rows, and service route counters retain their spacing.

  • [Cloud] Authenticated portal workflows recover from deleted workspace selections and page errors; resilience and snapshot comparisons load, deletion dialogs work, fixture lists refresh after writes, and fitness authoring sends supported evaluator settings. Cookie reloads restore tokens before loading protected pages. Theme toggles, deployment slugs, actor labels and action accessibility are corrected. (#1144)

  • [DevX] cargo install --locked mockforge-cli no longer warns about yanked dependencies (chacha20 0.10.0 and spin 0.9.8/0.10.0 bumped to their patched releases).

  • [DevX] GDPR erase on the SQLite backend did nothing (delete_user_data_cascade returned 0). It now matches the Postgres store. (#1087)

[0.3.229] - 2026-10-01

Changed

  • [Cloud] Tenant isolation is now also enforced in the database for every org-scoped table (36 tables under Postgres row-level security, up from 5). Request-path queries run bound to the caller’s org; background workers, webhooks and platform-admin paths run on the owner role. Requires the owner role (DATABASE_URL) to have BYPASSRLS; the migration refuses to apply otherwise. Startup now logs which roles back each pool and flags a misconfigured one at ERROR. (#1087)
  • [Cloud] PUT /api/v1/organizations/{org_id}/quota is now platform-admin only. Org owners can no longer set their own quota overrides, because overrides are merged over plan limits. GET now requires membership in the org. (#1087)
  • [Cloud] Row-level security now also covers 38 tenant tables that have no org_id column of their own (workspace, hosted-mock and other child tables). Each is isolated through its parent’s org, and per-user tables are scoped with a new app.current_user_id setting. (#1087, #1120)
  • [Cloud] Requests without an organization header now resolve to an org the user belongs to even when they own none (SSO-provisioned members, or users who deleted their personal org). Previously every such request returned 404. (#1087, #1117)
  • [DevX] Kubernetes manifests and the Helm chart now meet the “restricted” Pod Security Standard (non-root uid 999, no privilege escalation, all capabilities dropped), and liveness/readiness probes use the HTTP port instead of the auth-protected admin port. (#1118)
  • [DevX] Dependency refresh: 33 patch and minor updates, including tokio 1.53.1 and hyper 1.11. (#1104)

Fixed

  • [Cloud] The registry API no longer occasionally drops a request mid-flight (clients saw a closed connection or 502). The request-logging middleware held a tracing span open across an await, which could panic once a request moved between worker threads.
  • [Cloud] Security: any authenticated user could read or overwrite any org’s quota overrides. (#1087)
  • [Cloud][AI] Security: POST /api/v1/organizations/{org_id}/mockai/generate-openapi-from-traffic did not check that the caller belongs to the org. (#1087)
  • [Cloud] Security: the GDPR data export included pending invitation payloads, which let a plain member redeem an invite meant for someone else. (#1087)
  • [Cloud] GET /api/v1/organizations/{org_id}/incidents/stats no longer returns 500 once the org has a resolved incident. (#1087)
  • [Cloud] Security: a workspace could aim a chaos campaign at another org’s hosted mock and inject faults into it. Campaign targets are now checked against the caller’s org at create, trigger and snapshot restore, and the internal chaos toggle requires the run that owns it. (#1124)
  • [Cloud] Security: adding a capture to a capture session did not check who owned the capture, so a replay could read another org’s captured request bodies. (#1124)
  • [Cloud] Capture sessions, clone models, monitored services, diff runs and fitness functions belonging to another org now return exactly the same “not found” response as missing ones. (#1087, #1128)
  • [Reality][AI] MockAI no longer stores a session for every write request that arrives without a session ID. Those sessions were never read again and every write waited on one shared lock, so throughput fell steadily under sustained load (about 2x faster writes, flat memory). Per-request fixture-matching logs are now at debug level instead of warning. (#1125)
  • [Cloud] Returning visitors no longer see “Something went wrong” after a cloud UI deploy: the app’s entry JS and CSS are content-hashed so browsers can’t keep a stale copy. (#1116)

[0.3.228] - 2026-09-30

Added

  • [Reality] The mock Kafka broker can filter messages so it counts or verifies them without keeping every payload in memory. (#992)

Fixed

  • [Cloud] Hosted mocks now require a per-deployment management token for writes to MockForge’s control routes (/__mockforge/*, /api/chaos, /api/recorder, and the other management APIs). Previously anyone who knew a hosted mock’s URL could change it. Reads and your mocked API are unaffected, and self-hosted servers don’t use a token. Owners can reveal the token on the Hosted Mocks page. (#1105)
  • [DevX] Windows release binaries build again (a Unix-only socket option in bench-qos broke every Windows build since 0.3.223). (#1101)

[0.3.227] - 2026-09-30

Added

  • [Reality] mockforge bench-chunked gains --rps N (per-target cap on request starts per second), --cps (new TCP/TLS connection per request), and campaign mode: --rounds N / --repeat-until <duration> re-run the whole pass into <output>/round_N/, with per-round stats in campaign.jsonl and round-summaries/, and --keep-rounds N rotating old round dirs, matching mockforge bench. (#79)
  • [Cloud] Redesigned app shell for the logged-in portal: new sidebar, top bar, search and menus, refreshed shared UI primitives, and a new dashboard; every page moved onto the new frame. (#1086)

Fixed

  • [Cloud] GDPR account erasure no longer fails for users who have audit-log rows. (#1093)
  • [Reality] bench-chunked --chunk-interval-ms now sends the first chunk immediately and waits only between chunks. Previously it waited before the first chunk and sent the last two back to back. (#79)

[0.3.226] - 2026-09-29

Added

  • [DevX] Response overrides now work in mockforge serve. Rules come from a new overrides: list in mockforge.yaml, MOCKFORGE_HTTP_OVERRIDES_GLOB files, and a new MOCKFORGE_HTTP_OVERRIDES JSON array. With --admin, GET/PUT /__mockforge/overrides reads and replaces the live rules without a restart; an invalid set returns 400 and keeps the previous rules. Rules gain name and enabled. (#1088)
  • [DevX] Admin UI Overrides page to toggle, reorder, edit, and save override rules for the running mock (self-hosted) or a hosted mock (cloud). (#1095)
  • [Cloud] Per-hosted-mock override rules: GET/PUT /api/v1/hosted-mocks/{id}/overrides stores rules on the deployment, passes them to new machines, and pushes them live to running ones over the private network. (#1094)

Fixed

  • [DevX] tag: override targets match the operation’s real OpenAPI tags, and when: conditions see request headers, query, and body. Invalid JSON pointers are rejected instead of silently patching the whole body, and regex targets work in rule sets loaded from config (including gRPC). (#1088)
  • [Cloud] Redeployed hosted mocks now start their admin server, so the resilience dashboard and override push can reach them. (#1094)
  • [Cloud] Plugin registry search no longer returns 500 for the default “popular” sort and the “security” sort. (#1082)
  • [DevX] The admin UI top-bar search suggests pages and navigates on Enter. (#1082)
  • [Cloud] Bump wasmtime and wasmtime-wasi to 36.0.16 for RUSTSEC-2026-0316 and RUSTSEC-2026-0314. (#1092)

[0.3.225] - 2026-09-27

Added

  • [Reality] mockforge bench-chunked --targets-file <file> sends real Transfer-Encoding: chunked traffic to every target in a multi-target file in parallel (--max-concurrency, default 10). It uses the same file format as bench --targets-file, including per-target auth/headers/spec. Per-target artifacts go to <output>/target_N/, with a roll-up in chunked-multi-target-summary.json. (#79)

[0.3.224] - 2026-09-24

Added

  • [Reality] Campaign mode now supports --no-k6-logs (skips k6-output.log and conformance debug sidecars; k6 output is drained instead of buffered) plus per-round aggregate artifacts: round_N/round_summary.json, round_N/all_targets.csv, durable campaign.jsonl, and round-summaries/ copies. New --keep-rounds N prunes old round directories during a campaign while preserving campaign-level stats, and k6 scripts are generated once per target and reused across rounds. (#79)

[0.3.223] - 2026-09-18

Added

  • [Reality] Multi-target --repeat-until <duration> and --rounds N cycle the full targets list so low concurrency can still stress every server over a longevity window without manual restarts. Pair with a short --duration (per-batch k6 lifetime). (#79)

[0.3.222] - 2026-09-16

Fixed

  • [Reality] Longevity / huge-spec k6 runs no longer emit a Trend+Rate pair per OpenAPI operation by default when ops >= 500 or duration >= 1h (--per-op-metrics / --no-per-op-metrics to force). --max-concurrency auto-caps to 3 for huge specs, and SIGKILL gets an OOM hint. (#79)

[0.3.221] - 2026-09-12

Fixed

  • [Contracts] OpenAPI 3.1 schema type arrays (["string", "null"]) are coerced to OAS 3.0 type + nullable so the spec loads. LLM-generated specs failed with invalid type: sequence, expected a string and never extracted operations. (#79)

[0.3.220] - 2026-09-12

Fixed

  • [Reality] traffic-breakdown.json no longer repeats unique / total / expected_requests next to unique_cases / projected_*. Those aliases were a one-release bridge and got read as k6 wire counts. unique_cases is still the YAML case count (not traffic on the wire). projected_per_second / projected_over_run stay the plan. (#79)

[0.3.219] - 2026-09-10

Fixed

  • [Reality] HTTPS + ALPN HTTP/2 was rejecting WAF Connection headers (http2: invalid Connection request header). The header stays on the wire (it is the hop-by-hop test); k6 is forced onto HTTP/1.1 via GODEBUG=http2client=0 when --wafbench-verbatim is set or any request has a Connection header. generate-only prints the same prefix for a manual k6 run. (#79)

  • [Reality] traffic-breakdown.json fields are the plan, not k6 counters: unique_cases (YAML case count), projected_per_second (unique_cases * rps), projected_over_run (unique_cases * rps * duration). unique / total / expected_requests stay as aliases for one release. expected_requests_unit is dropped. (#79)

Added

  • [Reality] Multi-target runs print estimated wall clock: ceil(targets / max-concurrency) * duration. --vus and --rps are per target, not shared. (#79)

[0.3.218] - 2026-09-07

Fixed

  • [Reality] Static k6 paths are JSON-encoded and concatenated onto BASE_URL, so WAF URIs containing \x (Werkzeug UNC /static/\\attacker.com\share\x) no longer land in a JS template literal. k6/goja treated \x as a hex escape and exited before sending any request (invalid escape: \x: len("") != 2). The wire URI is unchanged. validate_script now rejects a bare \x hex escape in-process. (#79)

  • [Reality] traffic-breakdown.json field expected_over_duration is now expected_requests (HTTP count over the run, not seconds). When --rps is unset the value is null instead of inventing rps=1, which made a 60s run look like a duration of 300. (#79)

[0.3.217] - 2026-09-04

Fixed

  • [Reality] OpenAPI header parameters named Content-Length, Host, or Transfer-Encoding are no longer invented from the schema (#79). Srikanth’s Amazon S3 spec listed Content-Length as an integer header; generation filled 42 on empty-body POSTs and k6 dropped every request (Content-Length header \"42\" doesn't match actual body length of 0). k6 now owns those headers. Verbatim / user-overridden values are kept.

  • [Reality] Colliding WAFBench case titles no longer emit duplicate k6 const names (#79). A 32-target --wafbench-verbatim run with 31 YAML files sharing titles like normal request allowed failed every target with k6 exit 107 (ScriptException) and 0 requests. Identifiers and metric names now get a _2, _3, … suffix.

Added

  • [Reality] Traffic-file breakdown reprints at end of run with unique vs total (unique * RPS) and writes traffic-breakdown.json under the output dir for automation (#79).

[0.3.216] - 2026-08-31

Fixed

  • [Reality] A missing --wafbench-dir path is now a hard error instead of a warning plus an empty payload pool (#79). On 0.3.215, mockforge bench --wafbench-dir missing.yaml --spec ... --targets-file ... still generated a k6 script; getNextSecurityPayload() then returned undefined and goja threw Cannot convert undefined or null to object. The command now exits with WAFBench path does not exist. Defense in depth: an empty pool returns [] rather than undefined.

Added

  • [Reality] After a traffic file loads, print per-file sent / attack(expected 403) / normal(expected 200) / omitted counts so a multi-YAML run has a checklist for proxy-log review (#79).

Security

  • [Security] RUSTSEC-2026-0269: bumped wasmtime 36.0.13 to 36.0.14 (filesystem sandbox escape on trailing slashes). Same 36.x line as the rest of the plugin-loader pin.

[0.3.215] - 2026-08-30

Fixed

  • [Reality] --wafbench-verbatim now works with --targets-file (#79). The single-target path already sent traffic-file requests as written and made --spec optional, but --targets-file dispatched into ParallelExecutor first. That path still required a spec and built templates from spec operations, so the same command either died with No spec files provided or fuzzed spec URLs. ParallelExecutor now loads verbatim templates, keeps --spec optional, and calls security_testing_enabled() instead of recomputing the injection flag inline. --base-path / no longer prefixes a second slash onto paths that already start with /.

[0.3.214] - 2026-08-23

Added

  • [Reality] New mockforge bench --wafbench-verbatim sends each traffic case exactly as written instead of extracting an attack payload from it (#994, #79 round 66 / Srikanth on 0.3.213). His WAF rule chained on ARGS:redirect_uri and ARGS:response_type never fired, and the run still went green, which for a security tool is worse than an error. The cause: by default a case’s uri is treated as a CRS attack string hidden in a query parameter, so extract_uri_payload keeps only the FIRST parameter’s value, discards the path, and re-attaches the survivor to a spec-derived endpoint as ?test=<payload>. /oauth/authorize?response_type=totally-unsupported&redirect_uri=https%3A%2F%2Fevil...&state=s1 therefore went out as roughly GET <spec-endpoint>?test=totally-unsupported, with redirect_uri absent entirely. That behaviour is correct for CRS/WAFBench files, where one attack string is the whole test, so this adds a mode rather than changing the default. With the flag, method, full URI, headers and body are sent as given: no extraction, no path substitution, no test= injection, no spec-endpoint cycling, and --spec no longer supplies the endpoints. The URI is preserved byte for byte (query params are deliberately not parsed and rejoined, because for charset and traversal cases the encoding IS the payload). Real-binary verified against his own case and his 8-case file. Also documents that --wafbench-cycle-all affects payload selection only and does not change targeting.

  • [Reality] --wafbench-verbatim now genuinely sends requests untouched (#997). Found by capturing what the flag actually put on the wire rather than by reading the generated k6 script: --wafbench-dir feeds two consumers, and while verbatim mode stopped the template from extracting payloads, the security layer still read the same file as a payload POOL and appended &test=<payload> to every request at a later stage. That corrupted the exact cases the user asked to be sent literally, and it attached attack payloads to expected: 200 cases, so a correctly-behaving WAF would block them and the run would report failures the user never wrote. Inventing failures is as damaging as the false passes #994 fixed. The gating flag had been recomputed inline at four render sites, the #79 drift shape, and is now a single security_testing_enabled() method guarded by a test that fails if inline copies return. --security-test combined with verbatim now warns and is ignored rather than silently mutating traffic. --spec is optional in verbatim mode, since the traffic file supplies every request.

  • [Reality] Traffic cases marked omit_rule: true are skipped with an explanation instead of being parsed and silently dropped (#997). The field marks a baseline to be sent with the rule under test disabled; mockforge cannot toggle a WAF rule, so the case previously went out byte-identical to its non-omitted twin while asserting the opposite status. Exactly one of the pair always failed regardless of whether the rule worked, which defeats the only purpose of a baseline.

Fixed

  • [DevX] Documented the 41 MOCKFORGE_* environment variables that were read in code but absent from user-facing docs, which had left the docs/code drift gate red on every PR regardless of content. Covers the previously undocumented operator surface: plugin host, plugin egress proxy, test runner, platform LLM, capture forwarding, contract-diff and drift body limits, Kafka offset persistence, OTLP port, hosted overage ceiling, PagerDuty endpoint override. Defaults were read from the code rather than guessed, and three easy-to-miss behaviours are called out: MOCKFORGE_PLUGIN_HOST_SIGNATURE_MODE silently falls back to optional on an unrecognised value, and MOCKFORGE_SSRF_ALLOW_LOOPBACK / MOCKFORGE_SSO_ALLOW_INSECURE_ISSUERS relax SSRF protection and are test-only.
  • [DevX] Added a WAF Testing page to the book (#79). --wafbench-dir had no documentation at all, which is why targeting had to be explained by hand on the issue. Covers the two accepted file shapes, the payload-extraction vs verbatim distinction that decides whether a rule fires, a targeting matrix for the flag combinations, that --wafbench-cycle-all affects payload selection only, and why omit_rule cases are skipped.

[0.3.213] - 2026-08-20

Fixed

  • [Contracts] OpenAPI specs whose operations omit responses now load instead of aborting the run (#79 round 65 / Srikanth on 0.3.212). His proxy-generated spec failed outright with missing field \responses`, and the error named no path or method. The spec is genuinely non-conformant (OpenAPI 3.x marks responsesrequired, and 63 of its 70 operations omit it), but refusing it is the wrong trade: request generation, load testing and conformance probing all derive from paths, parameters andrequestBodyand never readresponses`, so the missing field costs nothing we use while rejecting the document costs the whole run. Proxies and API-discovery tools emit specs like this routinely, because they observe requests and have nothing to say about responses. A narrow repair pass fills in only the mandatory field, never invents response content, and warns with the count of affected operations and what is lost (response-schema validation has nothing to check for them). Real-binary verified against his attachment: the run now loads and finds all 70 operations.

Added

  • [Reality] --wafbench-dir now accepts a simple {title, request, expected} YAML list in addition to the WAFBench document shape (#987, #79 round 65 / Srikanth). His LLM-generated traffic file was rejected with invalid type: sequence, expected struct WafBenchFile, which was accurate about what failed but silent about what would have worked. The WAFBench shape exists to carry CRS rule IDs and provenance that a generated file has no reason to contain. The simple form maps 1:1 onto the internal representation (body becomes data, titles are synthesised when absent), so the rest of the security-test pipeline is untouched. expected accepts 403, [403, 406], or {status: ...}, and an unparsable expectation yields no status rather than dropping the case, since the request is still valid traffic. When both shapes fail, the error now names both with the parse error for each. Real-binary verified against his unmodified file: 8 cases, 24 payloads.

Security

  • [Security] RUSTSEC-2026-0258 (h2 unbounded empty DATA frames): bumped h2 0.4.15 to 0.4.17, which is the instance that serves HTTP here via hyper 1.x / axum. The remaining h2 0.3.27 is reached only through the AWS SDK client path and is ignored with reasoning recorded in audit.toml: 0.3.27 is the latest 0.3.x and upstream patched only the 0.4 line, and the flaw concerns queueing empty frames from a peer, where on that path we are the client talking to AWS KMS/STS over TLS. Advisory is rated low severity.

[0.3.212] - 2026-08-03

Fixed

  • [Reality] --conformance-basic-auth (and --conformance-headers, where --auth-bearer lands) now reach the wire on multi-target runs (#79 round 64 / Srikanth on 0.3.210). His mockforge bench --use-k6 --targets-file vs_list3.json --conformance-basic-auth user:pass ... sent no credentials at all, absent from both his PCAP and his proxy, while the identical single-target invocation worked. Round 47 taught parse_headers() to fold those auth shortcuts into the shared header map so the same flags work for a plain load run without --conformance, and both ends of the chain were already correct (ParallelExecutor calls parse_headers(); the k6 generator merges custom_headers into every endpoint). The break was between them: execute_multi_target hand-copies BenchCommand field by field and set conformance_basic_auth: None / conformance_headers: vec![], nulling the fields before parse_headers() ran, so the fold had nothing to fold. Real-binary verified across two targets: grep -c Authorization on the generated k6 scripts goes 0,0 to 3,3, carrying Basic dXNlcm5hbWU6cGFzc3dvcmQ=. Adds a drift guard asserting every field parse_headers() folds survives that clone, because field-by-field struct literals drop fields silently. Note that --validate-requests and --export-requests are conformance-run features (read only inside execute_conformance_test); they no-op on a plain load run in single- and multi-target alike, and need --conformance.
  • [Security] RUSTSEC-2026-0222: wasmtime 36.0.12 to 36.0.13, reached via wasmtime-wasi -> wiggle -> mockforge-plugin-loader. Lockfile only, a patch bump inside the existing 36.x line.
  • [Contracts] mockforge-registry-core no longer fails to compile for default-feature consumers. An associated const added in 0.3.211’s audit fix sat inside a #[cfg(feature = "postgres")] impl while its ungated caller and tests still referenced it, so cargo install mockforge-cli could not build. Nothing in CI covered that combination: the workspace test job runs --all-features and the registry server always builds with postgres. Moved to a module-level const.
  • [Contracts] Repaired the release pipeline itself. A stale doctest in mockforge-intelligence (broken since May) was failing cargo test --workspace --release in the Create Release job, which skipped everything after it, including the GitHub Release and the Fly deploy, which has needs: release. Production had therefore been serving 0.3.183 since 2026-06-19. Also aligned every Dockerfile builder with rust-toolchain.toml (1.75/1.90/1.91 to 1.96) after aws-smithy-types raised its MSRV past the pinned builder and broke container builds outright, and cleared the unused_qualifications errors that were reddening the Test job on every PR regardless of content.

[0.3.211] - 2026-07-27

Fixed

  • [Reality] Target-side HTTP protocol violations classify as "kind": "protocol" in conformance-network-events.json instead of generic "other" (#79 round 63 / Srikanth on 0.3.210). A WAF answering blocked security probes with a body that disagreed with its declared Content-Length trips Go’s server replied with more than declared Content-Length; truncated; those events previously mixed in with unclassifiable failures. Also covers malformed, protocol error, invalid header. Evaluated last, so eof/timeout/tls/connect keep their meaning and only other is re-labelled. Applied to all three k6 render paths with a regression test guarding both presence and ordering.

[0.3.210] - 2026-07-24

Added

  • [Reality] New mockforge bench --no-abort-on-error / --abort-on-error-rate <rate> flags to control the round-60 k6 memory safety valve (#79 round 62 / Srikanth on 0.3.209). The round-60 valve aborts a k6 run whose http_req_failed rate crosses 0.95 for 60s (OOM guard on dead targets), but that also stopped legitimate stress tests: Srikanth’s WAF/proxy targets legitimately reject ~95.2% of the probe traffic (fast non-2xx, zero transport failures), crossing 0.95 and aborting every run at ~2min. --no-abort-on-error drops the abortOnFail threshold so the run goes its full duration regardless of error rate; --abort-on-error-rate retunes the threshold (default 0.95). Wired through single- and multi-target k6 paths; default behaviour unchanged. Real-binary verified: the generated k6 script omits abortOnFail under --no-abort-on-error and renders rate<0.99 under --abort-on-error-rate 0.99.

[0.3.209] - 2026-07-22

Added

  • [Reality] New mockforge bench --dns-policy <policy> flag → k6 --dns "policy=<value>" (#79 round 61 / Srikanth on 0.3.208). Values: preferIPv4 (default), preferIPv6, onlyIPv4, onlyIPv6, any. Unblocks GEODB IPv6 tests where the target must stay a hostname (proxy routes by Host/SNI) but must be dialed over its AAAA record; k6/Go default to IPv4, which can’t be dialed from an IPv6 --source-ip (no suitable address found). preferIPv6 picks the AAAA record while keeping the hostname on the wire. Wired through single- and multi-target k6 paths; real-binary verified the launched k6 runs with --dns policy=preferIPv6.

[0.3.208] - 2026-07-21

Fixed

  • [Reality] k6 no longer OOM-kills (signal: 9) when a load target rejects/times-out ~every request (#79 round 60 / Srikanth on 0.3.207). The generated k6 load scripts now carry an abortOnFail safety valve on http_req_failed: a target failing >=95% of requests after a 60s grace period aborts (exit 99) instead of hammering a dead endpoint for the full duration and accumulating per-request memory. Legitimate runs under 95% failure are unaffected. Real-binary verified against a dead target: k6 stops at ~60s instead of running the full scenario. Applies to the standard-load and CRUD-flow templates.

[0.3.207] - 2026-07-19

Added

  • [Contracts] New “Security probes (owasp injection)” view in the self-test (#79 round 59 / Srikanth on 0.3.206 was WAF-testing and saw owasp: 0 caught / 8127 missed but Definite issues: none). The self-test now prints a per-injection-family breakdown of how many OWASP payloads the target accepted (status < 400) vs blocked (4xx), plus a conformance-owasp-accepted.json sidecar listing every accepted payload with method + URL. For a WAF each accepted payload is one it did NOT block; for a plain API it is expected (a string field accepts any string). Kept out of “Definite issues” (spec violations only) but surfaced on its own line. Verified against Srikanth’s capture (all 8127 payloads across 7 families accepted) and real-binary against mockforge serve.

[0.3.206] - 2026-07-16

Fixed

  • [Reality] Multi-target load no longer fails to start with exit status: 106 (k6 CannotStartRESTAPI) and zero requests (#79 round 58 / Srikanth on 0.3.205). Each parallel k6 was pinned to a fixed REST API port (6565 + index) that collides when already taken (orphaned k6 from a prior OOM-killed run, a second bench, a local service). k6 now binds an ephemeral port (--address localhost:0) instead; MockForge reads results from summary.json on disk, never the API. Real-binary verified with ports 6566/6567 occupied: a load that used to exit 106 on every target now runs.

Added

  • [Contracts] New “Definite issues” view in the self-test (#79 round 58 / Srikanth on 0.3.205 asked for a “for sure this is an issue” filter). A Definite issues (N) console section plus a conformance-definite-issues.json sidecar surface only unambiguous problems: a spec-valid request the target rejected, or any probe that drew a 5xx. Spec-valid “missed” negatives are excluded. Clarified that a “caught” 4xx is the target correctly rejecting a bad request, not a violation.

[0.3.205] - 2026-07-14

Added

  • [DevX] New mockforge bench --discard-response-bodies flag exposes K6_DISCARD_RESPONSE_BODIES=true as a first-class option (#79 round 57 / Srikanth on 0.3.204 asked for a flag instead of the env var for scale/stress runs). Opts a single-target load run into discarding response bodies (multi-target load already discards by default); no-op on conformance / self-test / extraction runs, which need the body. Real-binary verified: the launched k6 child carries the env var and data_received stays at header-only levels.

Changed

  • [DevX] The self-test console summary prints a one-line legend under the Negatives [...] lines explaining “caught” (target rejected a deliberately-bad request with a 4xx) vs “missed” (target accepted it), and that a high “missed” is not automatically a bug because many probes are spec-valid by construction (#79 round 57 / Srikanth on 0.3.204 asked how to read caught vs missed). The self-test-probes and capacity-sizing reference pages gain the same nuance and document the new flag.

[0.3.204] - 2026-07-13

Fixed

  • [Contracts] parameters:* negative probes are now recorded in conformance-request-violations.json, and the single-target self-test writes that file at all (#79 round 56 / Srikanth on 0.3.203: parameter violations were still absent from the logs). For his Apigee spec the parameter probes are all spec-VALID by construction (dropping the OPTIONAL $.xgafv query, adding an oversized/undeclared query param, or an unconstrained {instance} path value violate no schema), so the emitted-request validator found nothing to flag and stayed silent. Each parameters:* negative that produces no hard breach is now recorded as a typed parameter_negative_probe row explaining why it is not a schema violation; the single-target self-test calls the validator too (previously only the multi-target --targets-file path did); and --validate-requests now implies request capture. Real-binary verified against mockforge serve with a custom-verb Apigee spec: the violations file carries all three parameter probes (uri-too-long, bad-path-param, missing-query) alongside the genuine body_schema_violation / query_value_mismatch rows, in both single-target and --targets-file modes.
  • [Reality] k6 no longer gets OOM-killed (signal: 9 (SIGKILL)) during long, high-concurrency multi-target load runs (#79 round 56 / Srikanth on 0.3.203). The plain-load k6 only checks status codes but was buffering every response body in memory; over a multi-hour run at 10 VUs across 10+ targets the buffered bodies plus k6’s metric accumulation exhausted RAM and the kernel OOM-killer sent SIGKILL. The multi-target plain-load path now runs k6 with K6_DISCARD_RESPONSE_BODIES=true (safe there because bodies are never inspected). Real-binary verified: the launched k6 child process carries K6_DISCARD_RESPONSE_BODIES=true in its environment and data_received stays at header-only levels. The flag defaults off and is opt-in per executor; body-inspecting paths (conformance, extraction) are untouched.

[0.3.198] - 2026-07-02

Fixed

  • [Contracts] Self-test baseline probe filler is now spec-VALID (enum -> first member, boolean -> true, string body enums -> a valid member), so a request-body:* probe no longer trips spurious query_value_mismatch violations on alt/prettyPrint and body probes no longer show test-string enum noise (#79 round 51 / Srikanth on 0.3.196). Verified against mockforge serve: by-probe violations dropped 32 -> 12, request-body:* query violations now 0.
  • [Contracts] Multipart wire byte count now prefers k6’s Content-Length (the exact wire body size a proxy sees) over the reconstructed envelope, closing the 264-byte gap Srikanth reported on 0.3.196 (#79 round 51).

Added

  • [AI][DevX] New “Agent / LLM / MCP Traffic (Packet-Level)” reference page documenting Agent<->LLM, Agent<->Agent, and MCP interactions at the HTTP-packet level with real captures and PCAP-recording recipes (#79 / Srikanth on 0.3.196).

[0.3.197] - 2026-07-01

Added

  • [AI] Mock LLM endpoint real-model modes via --llm-mock-mode (#915): proxy (forward to --llm-mock-upstream), record (forward on cassette miss + save, replay on hit), replay (cassette only, offline; canned fallback). Default stays pure offline mock. New flags --llm-mock-upstream / --llm-mock-api-key / --llm-mock-cassette. Verified against mockforge serve by pointing one --llm-mock instance at another (no API key).

[0.3.196] - 2026-06-30

Added

  • [AI] Mock LLM endpoint: mockforge serve --llm-mock mounts OpenAI-compatible POST /v1/chat/completions + GET /v1/models and Anthropic-compatible POST /v1/messages with SSE streaming, so an agent can point its base URL at MockForge for scale/offline/failure testing (#912 / #79 Srikanth).
  • [AI] Mock MCP server: mockforge serve --mcp-mock mounts a JSON-RPC 2.0 endpoint at POST /mcp answering initialize / tools/list / tools/call / resources/list / prompts/list, so an agent acting as an MCP client can talk to MockForge (#913 / #79 Srikanth).

[0.3.195] - 2026-06-30

Fixed

  • [Contracts] Multipart wire byte count no longer comes out smaller than total; computed as disk-sum payload + ASCII multipart envelope instead of the UTF-8-undercounting raw.length (#79 round 50 / Srikanth on 0.3.194).
  • [Contracts] conformance-request-violations-by-request.json emits one row per URL with the deduped union of all violations and contributing checks, so a URL’s owasp/query checks no longer hide in a separate row from its body checks (#79 round 50 / Srikanth on 0.3.194).
  • [Contracts] Repeated self-test iterations no longer duplicate the same violation N times in the flat and grouped violation files (#79 round 50 / Srikanth on 0.3.194).

Added

  • [Contracts][AI] New --security-categories values llm-prompt-injection (OWASP LLM01 prompt-injection/jailbreak) and dlp (synthetic PII canaries) for agent-driven AI-attack and data-loss-prevention testing (#79 round 50 / Srikanth on 0.3.194).

[0.3.181] - 2026-06-17

Fixed

  • [DevX] Capture-viewer HTML status badge colour now follows the probe’s expected_status_range; a variant-b 400 reads green to match the exp 2xx-4xx badge (#79 round 36 / #875 / Srikanth).

[0.3.180] - 2026-06-16

Fixed

  • [Contracts] Embedded-content variant-b probes no longer flag 4xx responses as mismatches; only 5xx counts as failure (#79 round 35 / #859 / Srikanth).

[0.3.179] - 2026-06-15

Fixed

  • [DevX] response_schema_error strips description/example fields from the focused schema before truncation so type survives (#79 round 34 / #827 / Srikanth).
  • [Contracts] Per-endpoint summary path column matches the URL user sent: base_path prefixed (#79 round 34 / #828 / Srikanth).
  • [Contracts] Embedded-content variant-b probes skip when positive sample has no string field, instead of synthesizing a non-conforming envelope (#79 round 34 / #829 / Srikanth).

[0.3.178] - 2026-06-14

Added

  • [Contracts] Per-endpoint summary groups by spec path template, with a spec label for multi-spec runs (#79 round 33 / #823 / Srikanth).
  • [Contracts] MOCKFORGE_INJECT_RESPONSE_VIOLATIONS=true (+ --inject-response-violations) intentionally drops one required field from 2xx response bodies for negative-testing downstream proxies (#79 round 33 / #822 / Srikanth).

[0.3.177] - 2026-06-14

Fixed

  • [Contracts] Server-side conformance buffer now records content-types (415) violations from the MockAI router path too (#79 round 32 / Srikanth).
  • [Install] cargo install mockforge-cli no longer requires protobuf-compiler on Ubuntu 16.04 / RHEL 7; mockforge-grpc build uses a vendored protoc when PROTOC is unset (#79 round 32 / Srikanth).

Added

  • [Contracts] Per-endpoint traffic summary (sent count, status-class breakdown, request/response/query length p95) in bench-results/conformance-per-endpoint.json and a new section in conformance-report.html (#79 round 32 / Srikanth).

[0.3.176] - 2026-06-10

Fixed

  • [Contracts] Write requests (POST / PUT / PATCH / DELETE) now return spec-shape response bodies instead of MockAI’s hardcoded {id, status, data} envelope (#79 round 31 follow-up / Srikanth).

[0.3.175] - 2026-06-10

Fixed

  • [DevX] For required field missing errors, the printed schema is now the missing property’s own sub-schema, not the entire parent object (#79 round 31 / Srikanth).
  • [Install] cargo install mockforge-cli no longer requires OpenSSL 1.1+; the workspace is fully rustls-only (#79 round 31).

Added

  • [Server] mockforge serve --conformance-buffer-size N and --conformance-buffer-unique CLI flags mirror the round-29/round-30 env vars (#79 round 31 / Srikanth).

[0.3.174] - 2026-06-09

Fixed

  • [DevX] response_schema_error now prints only the sub-schema at the offending JSON Pointer instead of the full top-level schema (#79 round 30 / Srikanth).

Added

  • [Contracts] MOCKFORGE_CONFORMANCE_BUFFER_UNIQUE=true switches the violation buffer from FIFO to dedup-by-signature; every duplicate bumps a new occurrences field on the entry instead of consuming a new buffer slot (#79 round 30 / Srikanth).

[0.3.173] - 2026-06-08

Fixed

  • [DevX] response_schema_error message reads response body root: ... / response body at /<path>: ... instead of the ambiguous at /: ... (#79 round 29 / Srikanth).

Added

  • [Contracts] MOCKFORGE_CONFORMANCE_BUFFER_SIZE env var raises the server-side violation ring buffer above the default 256, capped at 64k (#79 round 29 / Srikanth).
  • [Contracts] Bench capacity advisory at run start when targets × VUs ≥ 150; estimates RAM / CPU and links to the new sizing doc.
  • [DevX] New book page reference/bench-capacity-sizing.md with sizing table, formulas, and sharding guide.

[0.3.172] - 2026-06-07

Fixed

  • [Contracts] Content-type-swap probes now send only ONE Content-Type (the reqwest header-append bug let axum’s JSON extractor accept). Smoke test: same 4 probes that returned 204 on 0.3.171 now return 415 (#79 round 28).
  • [Contracts] Server-side check_request_content_type flags Content-Type mismatches against requestBody.content keys; records a content-types category violation. (#79 round 28)
  • [DevX] response_schema_error embeds the expected schema JSON: at /: expected type string; expected schema {"type":"string"}. (#79 round 28)

Added

  • [Contracts] expected_status_range field on every CaseCapture; exp 4xx/exp 2xx-3xx badge on every card. (#79 round 28)
  • [DevX] “Only show mismatches” checkbox + per-cat clickable counts in the per-op By category column. (#79 round 28)

[0.3.171] - 2026-06-06

Fixed

  • [DevX] Capture HTML viewer paginates with cross-page filters; the round-25 + round-26 1000-card cap that hid 4xx/5xx probes is gone (#79 round 27 / Srikanth d3).

Added

  • [Contracts] Content-type swap variant (b): four request-body:embedded-content:* probes per JSON operation send a valid JSON envelope with an XML/YAML/multipart/urlencoded snippet stuffed into a string field. Flags servers that crash on the embedded content (#79 round 27 / Srikanth k variant b).

[0.3.170] - 2026-06-06

Fixed

  • [Contracts] TUI Conformance tab: detail modal now snapshots the violation’s text at Enter time (#79 round 26 / Srikanth re-test of 0.3.169). The round-25 identity-key re-anchor only worked when the clicked violation survived the 256-cap buffer; under heavy traffic it got evicted and selected stayed at a stale index. Snapshot + Esc-clear fixes it; regression tests cover both the index-shift and the on_data refresh path.
  • [DevX] response_schema_error is now human-readable (“at /: expected type string”) instead of broken Rust debug syntax (#79 round 26 / Srikanth). Falls back to jsonschema’s Display impl for the long-tail kinds.
  • [DevX] HTML report Negatives by category is now a single grouped table with a Family column prepended (#79 round 26 / Srikanth d2). The standalone family rollup section is gone; one table carries both axes.

[0.3.169] - 2026-06-05

Fixed

  • [Contracts] TUI Conformance tab: selecting a row no longer jumps to a different request when new traffic arrives on the next refresh tick (#79 round 25 / Srikanth follow-up).
  • [DevX] Capture HTML viewer no longer hangs the browser at 9000+ probes: content-visibility: auto per card, 200 ms debounced filter, hard cap at 1000 rendered cards with Showing N of M banner (#79 round 25 / Srikanth d follow-up).

Added

  • [Contracts] Content-type swap probe family request-body:content-type-mismatch:<variant> (#79 round 25 / Srikanth k). Four probes per JSON operation: xml / yaml / multipart / urlencoded.
  • [Contracts] --validate-response-schemas flag (#79 round 25 / closes round 21.3 / Srikanth a2 + a3). Validates every probe’s response body against the spec’s response schema for the actual status returned. Mismatches surface as response_schema_error in the JSONL and a red “Response schema mismatch” section in the per-probe HTML viewer card. Opt-in.
  • [DevX] HTML report: Negatives by category family rollup (Request body / Parameters / Security family) and a per-operation By category column showing mismatch breakdown (#79 round 25 / Srikanth d remainder).

[0.3.168] - 2026-06-04

Fixed

  • [Contracts] Geo-source-IP headers now ride on every self-test probe, not just the positive case (#79 round 24 / Srikanth f). Four negative-probe call sites and the security-probe path were dropping the geo IP. Regression test (geo_headers_present_on_every_probe_with_capture) added.
  • [DevX] Clickable count cells in the HTML report no longer dead-end when --report-missed-cap crops the drill-down (#79 round 24 / Srikanth e). Counts only link when their target row actually survives the truncation.

Added

  • [DevX] --conformance-self-test-capture now also emits a browser-viewable conformance-self-test-requests.html alongside the JSONL (#79 round 24 / Srikanth d). Self-contained, includes a filter toolbar and expandable per-probe cards.

[0.3.167] - 2026-06-03

Fixed

  • [Contracts][DevX] --source-ip now actually works with the k6 path (#79 round 23 / Srikanth correction on round-22 g1). The round-22 warning that said “k6 cannot bind a VU to a source IP from the script side” was wrong: k6 supports --local-ips natively (CIDR, ranges, and comma-separated single IPs). The k6 executor now forwards the CLI’s --source-ip straight to k6 run --local-ips, and the misleading warning is removed. Only the --conformance-self-test --use-k6 combo still fires a warning, because self-test returns before k6 launches and --use-k6 is a no-op there.
  • [DevX] Docs site is rebuilding again (docs.mockforge.dev had been stuck since the 2025-11-10 build because mdbook-toc 0.15.x stopped parsing mdbook’s preprocessor input). The TOC preprocessor was disabled (no page uses the <!-- toc --> marker anyway) and its cargo install step was removed from the deploy workflow, so the round-21 probe-label reference page resolves at https://docs.mockforge.dev/reference/conformance-self-test-probes.html.

Added

  • [Contracts][DevX] --conformance-self-test-capture flag (#79 round 23 / Srikanth c-iii deferred from round 22.5). When set alongside --conformance-self-test, every probe records method, URL, request headers/body and response status/headers/body to conformance-self-test-requests.jsonl (one JSON object per line) next to the JSON/HTML report. Bodies cap at 16 KiB per direction with request_body_truncated / response_body_truncated flags.
  • [DevX] HTML conformance report: count-cells in the “Negatives by category” and “Per-operation results” tables are now clickable links into the drill-down table below (#79 round 23 / Srikanth d). #miss-cat-<category> jumps to the first row of that category; #miss-op-<method>_<path-slug> jumps to the first row for that operation.
  • [DevX] HTML conformance report wording: “missed/caught” renamed to “Mismatched (non-4xx) / Matched (4xx)” across the cards, category table, per-operation table, and drill-down heading; the category status badge is now a plain PASS/FAIL (replacing “all caught” / “rejection gaps”) since the count column already conveys magnitude (#79 round 23 / Srikanth d wording).

[0.3.166] - 2026-06-02

Fixed

  • TUI Conformance: Enter in the Unknown view (u) opens Unknown Path Detail instead of the (wrong) Violation Detail (#79 round 22.1).
  • --source-ip / --geo-source-ip emit a warning when used with --use-k6 since k6 can’t bind a VU to a source IP (#79 round 22.2).

Added

  • --geo-source-ip headers wired into the k6 template; the rendered script rotates X-Forwarded-For / True-Client-IP / CF-Connecting-IP per iteration (#79 round 22.3).
  • --source-ip / --geo-source-ip accept start-end IPv4 ranges (e.g. 10.0.0.5-10.0.0.27) alongside CIDR and comma-separated lists (#79 round 22.4).
  • HTML report header links to the probe-label reference; “gaps” badge wording clarified to “rejection gaps” (#79 round 22.6).

[0.3.165] - 2026-06-01

Added

  • --report-missed-cap N flag for the HTML drill-down (#79 round 21.1). Default 200; 0 = no cap.
  • HTML missed-negative table gains an Expected column (#79 round 21.1). Addresses Srikanth’s (a1).
  • New book page: Conformance Self-Test Probes (#79 round 21.2). Canonical reference for every probe label.

Notes

  • Response-body shape validation alongside the response-code check (a2 / a3) is queued for a separate release.

[0.3.164] - 2026-06-01

Fixed

  • Shadow mode now gates 200 on the configured --base-path (#79 round 20). Paths outside the configured prefix (e.g. /api123/... when server is /api) return 404 even with --shadow enabled, matching pre-shadow semantics. path_in_base checks at the segment boundary, so /api123 is not under /api.

[0.3.163] - 2026-06-01

Fixed

  • Live-server route handler now resolves nested $ref pointers against the spec’s components (#79 round 19) — third schema-validator call site, missed by round 18.3. Dotted-name vCenter schemas resolve.

Added

  • --source-ip and --geo-source-ip accept CIDR ranges (10.0.0.0/28, 2001:db8::/126) capped at 256 hosts per range. IPv4 + IPv6 supported (#79 round 19).

[0.3.162] - 2026-05-31

Issue #79 rounds 17.1–18.5 consolidated into a single release. Intermediate version numbers (0.3.153–0.3.161) were never published.

Added

  • TUI Conformance: c copies the selected violation to clipboard (round 17.1); total_ok counter alongside total_seen for accurate pass/fail ratio (round 17.1).
  • --conformance-self-test schema-driven body mutator (round 17.2), security probes (round 17.3), spec-level audit (round 17.4), OWASP/WAF unification (round 17.5), self-contained HTML report (round 17.6).
  • GEODB multi-source-IP testing (round 18.5): --source-ip (real bind) + --geo-source-ip (forwarded-IP headers).

Changed

  • OWASP coverage table now explains the “-” rows with actionable category hints (round 18.4).

Fixed

  • --conformance-self-test honours --base-path (round 18.1); hard warning when every positive returns the same status (round 18.1); accurate bench header before spec parse (round 18.2).
  • Request-body validator resolves nested $ref pointers against the spec’s components map (round 18.3) — fixes the Vcenter.VM.DiskCloneSpec “Pointer does not exist” class of failures.

[0.3.152] - 2026-05-28

Changed

  • [Contracts][DevX] TUI Conformance export (e) now deduplicates by (method, path, category, reason) with a count + first_seen / last_seen window (#79 round 16).
  • [DevX] --conformance-self-test produces negatives for two previously-zero-coverage shapes: operations with a required body but no synthesised sample, and operations whose only spec input is a path parameter (parameters:bad-path-param probe).

[0.3.151] - 2026-05-27

Added

  • [Reality] mockforge serve --shadow CLI flag (#79 round 15) — first-class flag for shadow mode (alias for MOCKFORGE_SHADOW_MODE=true) so it can’t be forgotten.
  • [Contracts][DevX] Lifetime “seen total” counters for conformance violations + unknown paths — admin API total_seen field and TUI titles now show the true lifetime count alongside the 256-cap buffered count.

Changed

  • [DevX] Per-violation server log under target mockforge::conformance (enable with RUST_LOG=mockforge::conformance=debug) showing method/path/status/category/reason.
  • [DevX] TUI Conformance detail view + Top Offending Endpoints panel now wrap long lines so big paths/reasons are fully readable.

[0.3.150] - 2026-05-26

Fixed

  • [Reality] Server no longer OOM-killed at startup on large specs (#79 round 14) — router construction cloned the entire routes Vec into every per-route handler (O(N²) memory; ~260 GB for an 11,422-op spec). Fixed by sharing one validator via Arc across all handlers. Reproduced + verified with a 22,000-operation synthetic spec.

Added

  • [Reality][Contracts] Server-side shadow mode (MOCKFORGE_SHADOW_MODE=true) (#79 round 14) — returns 200 for unknown paths and spec violations while still recording them to the conformance + unknown-paths buffers (report-only / monitor mode for proxy-replay traffic). Startup prints a 👻 SHADOW MODE ON banner.
  • [Contracts][DevX] Status column on the TUI unknown-paths view — surfaces the HTTP status the server returned (404 normally, 200 in shadow mode).

[0.3.149] - 2026-05-25

Added

  • [Contracts][DevX] mockforge bench --conformance --conformance-self-test (#79 round 13 (4)) — positive + per-category negative driver. Sends one valid request and per-category negatives (empty body / wrong-type body / missing required query / missing required header) per spec operation; reports how many the server correctly rejected with 4xx. Writes conformance-self-test.json and emits a warning when any negative slipped through.

[0.3.148] - 2026-05-25

Fixed

  • [Contracts][DevX] Conformance buffer now actually fires on the default-flow handlers (#79 round 13) — the MockAI and AI handlers bypassed validation entirely, so violations never populated for default-flow routes. Extracted OpenApiRouteRegistry::run_validation_with_recording and called it at the entry of each handler.

Added

  • [Contracts] New response-shape violation category — surfaces when a requested status code isn’t defined in the spec for that operation.
  • [Contracts][DevX] New unknown-paths feed + admin endpoint + TUI view — separate ring buffer tracks requests whose path didn’t match any spec route. GET /__mockforge/api/conformance/unknown-paths; TUI u toggles between violations and unknown-paths views.

[0.3.147] - 2026-05-25

Changed

  • [DevX] TUI Conformance tab moved before Verification (#79 round 12 follow-up) — Verification’s Tab cycles internal fields so it acts as a dead-end for plain Tab nav. Putting Conformance earlier in the strip keeps it reachable.

[0.3.146] - 2026-05-25

Fixed

  • [DevX] TUI Conformance tab now appears + admin server exposes the violations endpoint (#79 round 12 hotfix) — v0.3.145 had two bugs: (1) ScreenId::Conformance was added to the enum but ConformanceScreen::new() was missing from App::new’s screens vec, so the tab silently dropped from the header; (2) the endpoint was only wired into mockforge-http’s management router (mock-traffic port), not the admin server the TUI polls. Fixed both, plus added an app_screens_match_screen_id_all regression test.

[0.3.145] - 2026-05-24

Added

  • [Contracts][DevX] New Conformance TUI screen + /__mockforge/api/conformance/violations endpoint (#79 round 12) — server-side counterpart to the bench-side conformance suite; every incoming request the OpenAPI router rejects for a spec violation (400/422) is captured to a bounded ring buffer and rendered in a new TUI tab.

Fixed

  • [DevX] mockforge bench --conformance --operations 'METHOD,…' now actually filters (#79 round 12) — execute_conformance_test was silently ignoring self.operations / self.exclude_operations. Also relaxed SpecParser::filter_operations to accept method-only form ("GET") without requiring "GET /path".
  • [Reality] Multi-target bench summary now includes connection + iteration counts (#79 round 12).
  • [Cloud] pillar_tracking no longer drives sqlx::pool::acquire “slow acquire” spam under load (#79 round 12) — added a 20-task in-flight cap at the recorder entry so over-pressure events are dropped immediately instead of queuing on the analytics-DB pool’s 30s acquire timeout.

[0.3.144] - 2026-05-24

Fixed

  • [Reality] OpenAPI router accepts request bodies up to 50 MiB by default (was 2 MiB axum default) — closes the “200 OK before all chunk requests arrived” PCAP behaviour Srikanth reported on Issue #79
    • Root cause: axum 0.8’s Bytes and Option<Json<Value>> extractors enforce a 2 MiB DefaultBodyLimit. Above that, the body gets truncated and the handler runs without consuming the rest of the request — hyper sends the response and TLS Close Notify while the client is still uploading the body. Reproduced locally with a 3 MiB JSON body to the demo spec.
    • Fix: every OpenApiRouteRegistry::build_router_* variant now mounts axum::extract::DefaultBodyLimit::max(...) with a 50 MiB default, configurable via MOCKFORGE_HTTP_BODY_LIMIT_MB.
  • [Cloud] pillar_tracking no longer floods logs with one WARN per dropped event under load (#79 round 11)
    • Per-event failures are now DEBUG; a single aggregated pillar_tracking: dropped X events in the last 60s due to analytics-DB pressure WARN fires at most every 60 seconds.

[0.3.143] - 2026-05-23

Fixed

  • [DevX] Republish of 0.3.142 — fixes broken [email protected] install (#79 round 10 hotfix)
    • cargo install [email protected] failed with error[E0432]: unresolved import \crate::database::Database`inmockforge-http/src/handlers/threat_modeling.rs:29andlib.rs:2387. The databasemodule was moved tomockforge-intelligencein #611, but twouse crate::database::Database;statements weren't gated behind#[cfg(feature = “database”)], so default-feature builds (which is what cargo installuses) failed to compile. Fix landed onmain` in #616/#618 but was not in the 0.3.142 tag.
    • 0.3.142 of the broken crates (cli, http, import, pipelines, proxy, workspace, core, bench, chaos, collab, recorder, registry-server, k8s-operator, vbr, sdk, test, reporting, ui) yanked from crates.io. 0.3.143 republishes the same #79 round-10 changes from a known-good main commit.

[0.3.142] - 2026-05-21

Changed

  • [DevX] Pre-flight --vus recommendation caps at 1000 for huge specs (#79 round 10)
    • Srikanth’s 11,422-operation spec at --rps 100 (9.4ms baseline) produced a recommendation of ~10,740 VUs — mathematically correct but practically absurd. The right answer for that workload isn’t “spin up 10K VUs”, it’s “shrink the workload.” 0.3.142 caps the printed recommendation at 1000 and, above the cap, steers users toward --operations/--exclude-operations filters or dropping --rps for closed-model loading.

Added

  • [DevX] Iteration coverage in bench summary (#79 round 10)
    • New Iterations: X complete × N ops = Y ops fully exercised line appears whenever k6’s iterations.values.count is non-zero. When the run ends mid-iteration (large spec, undersized VUs), a follow-up line surfaces the extra requests from the partial pass so users know the last iteration didn’t cover every operation in the spec.

Fixed

  • [DevX] scripts/check-changelog.sh now uses the PR-wide diff in CI instead of git diff-tree -r HEAD (which returns the empty combined diff on the synthetic refs/pull/<N>/merge commit actions/checkout uses). Previously every PR whose CHANGELOG.md edit landed in a commit that the merge didn’t have to reconcile would fail the “Changelog Validation” gate even though the workflow’s own outer condition correctly detected the edit (caught on #595’s release PR). Now switches modes on $GITHUB_BASE_REF: PR-wide git diff --name-only origin/$GITHUB_BASE_REF...HEAD in CI, single-commit diff-tree -r HEAD locally for the cargo-release flow.

[0.3.141] - 2026-05-20

Fixed

  • [DevX] mockforge-foundation::pillars doctests now reference the actual crate path (release-gate fix)
    • All 9 doctests imported use mockforge_core::pillars::..., but the Pillar enum lives in mockforge-foundation itself. The mismatch caused cargo test --doc -p mockforge-foundation to fail with cannot find module or crate `mockforge_core` , which gates the Release workflow’s cargo test --workspace --release step — so the v0.3.140 tag’s Create Release job failed and Publish-to-crates.io was skipped. Replaced mockforge_core::pillars → mockforge_foundation::pillars across all 9 doctests. 11 doctests now pass.
    • 0.3.140 was never published to crates.io; this release ships the round-9 bench fix originally intended for that version, plus this doctest fix on top.

[0.3.140] - 2026-05-20

Fixed

  • [DevX] Pre-flight --vus probe now factors in operations-per-iteration (#79 round 9)
    • The round-8 probe assumed 1 iteration = 1 request, but k6’s constant-arrival-rate counts iterations and every iteration calls every operation in the spec. Srikanth’s 12-op spec at --rps 100 with 15ms latency reported “–vus 5 is sufficient” and then k6 still emitted “Insufficient VUs, reached 5 active VUs” mid-run because real iteration time was 15ms × 12 ops, not 15ms.
    • Fix: ProbeResult::required_vus(rps, num_operations) now multiplies by spec operation count. Same call site change in command.rs. New tests required_vus_scales_with_operation_count and required_vus_treats_zero_operations_as_one. The pre-flight progress / warning lines now print the operation count so users see what the math used.

[0.3.139] - 2026-05-19

Added

  • [DevX] Adaptive pre-flight latency probe for --vus sizing (#79 round 8)
    • mockforge bench --rps N --vus M now does a 3-request HEAD/GET probe of the target before launch to measure baseline latency, then recommends --vus based on ceil(rps × measured_latency_secs) + 1 instead of the static “100ms / 10 req-per-VU” heuristic. Fixes a false-positive on Srikanth’s fast targets (~2ms response time) where the old heuristic warned “bump to –vus 100” when –vus 5 was actually plenty.
    • If the probe can’t reach the target (auth-gated, strict WAF, etc.), falls back to the previous 100ms heuristic so the warning still fires when warranted. When the probe succeeds AND --vus is sufficient, prints a confirmation line so users know the size check passed.
  • [Reality] “Connection reuse NOT detected” diagnostic in bench summary (#79 round 8)
    • When tcp_connect_samples > 5 × vus_max in pooled-reuse mode (no --cps), the bench reporter now prints a yellow warning explaining the target is closing sockets between requests. Addresses Srikanth’s 0.3.137 question: “I expected 5 connections with –vus 5 but see 7425” — the counter is correct, the proxy isn’t pooling. The new line makes that interpretation explicit so users don’t have to guess.

[0.3.138] - 2026-05-19

Added

  • [Cloud][Reality] Cloud-mode Time Travel — controllable virtual clock on hosted-mock deployments (#466, #527)
  • [Cloud][AI] Cloud-mode Test Generator — async LLM jobs over runtime_captures (#469, #529)
  • [Cloud][Reality] Real-time runtime-logs SSE via Fly NATS subscription (#556, #559)
  • [Cloud][Reality] OTLP gRPC trace receiver alongside HTTP/JSON (#548, #566)
  • [Cloud][Reality] Per-capture cloud forwarder with backpressure + retry (#553, #564)
  • [Cloud][Reality] Trust-root boot — plugin host fetches + refreshes active trust roots from registry (#549, #565)
  • [Cloud][Reality] HSM-backed platform signing-root rotation via AWS KMS (#550, #567)
  • [Cloud][Reality] Email notification channel via EmailService (#551, #557)
  • [Cloud][Reality] PagerDuty notification channel via Events API v2 (#552, #558)
  • [CI][Reality] Nightly hosted-mocks smoke workflow (#554, #563)

Changed

  • [DevX] pr_generation moved out of mockforge-core into mockforge-intelligence; intelligence → core dep cycle broken (#562 phase 1, #571)
  • [DevX] ADR auditing mockforge-http for intelligence/proxy extraction (#555, #561)

Fixed

  • [DevX] CI rust-cache no longer poisons builds with dangling target/*.d paths (#446, #570)
  • [UI][Cloud] CloudTestGeneratorView import path corrected (#547)

Note: Time Travel (#527) and Test Generator (#529) were initially attributed to 0.3.137 in the historical changelog block below. Both PRs landed after the v0.3.137 tag (efa43d20) had already been published, so they actually ship in 0.3.138.

[0.3.137] - 2026-05-18

Added

  • [Cloud][Reality] Cloud-mode World State — per-deployment graph + snapshot + layers + slice-query surface (#464, #528)
    • Registry proxies 5 HTTP endpoints (snapshot, snapshot/{id}, graph?layers=…, layers, query) over Fly 6PN to {fly-app}.internal:3000/api/world-state/*. Wire format mirrors cloudResilience and cloudTimeTravel: { runtime_state: "live" | "unreachable", data }. unreachable carries data: null so the UI renders an honest empty state.
    • New CloudWorldStateView reuses the existing StateLayerPanel, WorldStateGraph, and StateNodeInspector components so the visualization is identical to local mode. Deployment selector auto-picks the first active hosted-mock; multi-deployment orgs get a dropdown. 5-second polling matches the local TanStack Query refetchInterval.
    • 'world-state' added to cloudNavItemIds. WebSocket /stream upstream is intentionally not proxied — polling parity is functionally equivalent for the cadence the local UI uses, and ws-tunneling through 6PN is a follow-up.
  • [Cloud][Reality] Cloud-mode Time Travel — controllable virtual clock on hosted-mock deployments (#466, #527)
    • 7 clock-control endpoints proxied (status, enable, disable, advance, set, scale, reset). Targets the hosted mock’s main HTTP port (3000) — not the admin port — because the time-travel router mounts there for reachability when admin isn’t publicly exposed.
    • New CloudTimeTravelView with a runtime-unreachable banner that disables the control fieldset so users don’t fire mutations that’ll bounce back. Cron jobs + mutation rules stay local-only — they manage scenario state, not a hosted mock’s single-process clock.
    • 'time-travel' added to cloudNavItemIds.
  • [Cloud][AI] Cloud-mode Test Generator — async LLM jobs over runtime_captures (#469, #529)
    • New cloud_test_generation_jobs table + 4 CRUD endpoints + SSE stream (GET .../jobs/{id}/stream) for live progress.
    • Background tokio worker drains the queue with FOR UPDATE SKIP LOCKED claims, processes up to TEST_GENERATION_WORKER_CONCURRENCY (default 4) jobs in parallel per tick, and dispatches via the same ai::client + ai::quota pipeline ai_studio uses — so quota and billing semantics stay consistent. BYOK skips the platform token quota; paid plans without BYOK succeed via the platform key (MOCKFORGE_PLATFORM_LLM_API_KEY + provider/model/endpoint env vars).
    • Worker is forgiving: best-effort JSON parse strips ```json fences, recovers from prose wrappers, falls back to a { raw_content } wrapper. Cancellation race is safe — terminal writes are gated on WHERE status = 'running' so a user-cancel mid-flight wins.
    • New CloudTestGeneratorView with job timeline + create form + expandable detail rows + SSE-driven sub-second updates on expanded non-terminal rows. 'test-generator' added to cloudNavItemIds.
  • [DevX] Pre-flight warning when --vus is too low for --rps (#79 round 6 follow-up, #543)
    • mockforge bench --rps N --vus M now warns before launch when M × 10 < N (rule of thumb: 1 VU at ~100ms latency sustains ~10 req/s). The warning suggests a higher --vus value (ceil(rps / 10)), so users hit by k6’s “Insufficient VUs, reached M active VUs and cannot initialize more” message know what to change.

Changed

  • [CI][Reality] release.yml gates Fly deploy + crates.io publish + Helm chart push on the release job’s cargo test --workspace --release (#447, #526)
    • All three downstream jobs (deploy-registry, publish, helm) now needs: release. A tag with red tests no longer ships to Fly / crates.io / the Helm repo.
  • [DevX] pr_generation moved out of mockforge-core into mockforge-intelligence and the intelligence → core cycle was broken (#562 phase 1, #571)
    • mockforge-intelligence dropped its mockforge-core dep, freeing mockforge-core to take a mockforge-intelligence dep. mockforge_core::pr_generation is preserved as a pub use re-export for backwards compat.

Fixed

  • [DevX] CI rust-cache no longer poisons builds with dangling target/*.d paths (#446, #570)

    • CARGO_HOME switched from per-run to per-runner-name so cached dep-info paths remain valid across runs on the same runner. Swatinem/rust-cache@v2 invocations now partition the cache key by runner.
  • [Reality] Client-side “Connections opened” counter now appears for --rps-only runs (#79 round 6 follow-up, #543)

    • Root cause: the parser was reading http_req_connecting.values.count from k6’s summary.json, but k6’s Trend metric never emits a count field — only avg/min/med/max/p(90)/p(95). The field was always absent, so tcp_connect_samples was always 0 and the connection-count line never printed for non---cps runs.
    • Fix: the generated k6 script now declares a dedicated mockforge_connections_opened Counter and increments it whenever res.timings.connecting > 0 (i.e. a fresh TCP socket was opened). The Rust parser reads this Counter’s count directly. Works for both --cps runs (≈ total requests) and pooled-reuse runs (≈ vus_max).
    • Also: TCP-connect / TLS-handshake timing lines now print whenever the Trend has a non-zero avg, not when count > 0 (which was unreliable). New test_connections_opened_counter_present regression test guards both the Counter declaration and the per-request increment.
  • [Reality] --scenario constant now runs at full VU concurrency from t=0 (#79 round 6 follow-up, #543)

    • Root cause: Srikanth reported that --vus 5 -d 600s took until the ~6-minute mark to reach 5 VUs and then ramped DOWN. The k6 template always wrote startVUs: 0, so even --scenario constant’s single {duration: '600s', target: 5} stage made ramping-vus linearly interpolate from 0 → 5 across the whole window.
    • Fix: for Constant, startVUs is seeded at max_vus so concurrency is at full from the start. Ramping scenarios (RampUp/Spike/Stress/Soak) still start at 0 and let their stages drive the curve. Guarded by test_constant_scenario_starts_at_target_vus.
  • [Cloud][Reality] Cloud Resilience dashboard could not reach hosted mocks over Fly 6PN (#468 follow-up, #542, #544)

    • mockforge serve --admin was binding the admin port to 127.0.0.1, so the registry proxy’s {fly-app}.internal:9080 reach failed silently (#542 — bind dual-stack). UI’s /api/resilience/* paths also sat behind auth middleware that doesn’t run in proxied cloud mode, so the proxy’s outbound calls 401’d (#544 — explicit exempt prefix). Both fixes were needed for the cloud Resilience tab to render live state instead of perpetual runtime_state: unreachable.
  • [UI][Build] Allow esbuild / vue-demi build scripts under pnpm 11’s managed-builds policy (#525, #533)

    • pnpm-workspace.yaml declares the two packages in onlyBuiltDependencies so production docker builds succeed.
  • [UI][Build] Pin pnpm to 10.15.0 in the docker stages (#525 follow-up, #536)

    • 10.15.0 predates the managed-builds policy that triggered #525 in the first place.
  • [UI][Cloud] Hide api-explorer from cloud sidebar (#459 follow-up, #537)

  • [CI][Docker] Explicit cosign login so signature push to GHCR succeeds (#546)

Cloud-parity meta tracker

This release closes #459 — the cloud-parity meta tracker for the 14 “Local only” nav items. 14 / 14 addressed: 8 shipped end-to-end across prior releases (Graph #460, Virtual Backends #461, Logs #462, Metrics-folded #463, World State #464, Observability #465, Performance-folded #467, Resilience #468), 4 explicitly kept local-only (Proxy Inspector #470, SMTP Mailbox #471, MQTT Broker #472, Kafka Broker #473), 2 land in this release (Time Travel #466, Test Generator #469).

[0.3.132] - 2026-05-12

Added

  • [Reality] Full chaos fault-category coverage in stats and /metrics (#79 round-4)
    • connection_error fault now records at the HTTP layer when connection_error_kind: http_503 (previously only TCP-level kinds had counters). New jitter and bandwidth_throttle counters + matching Prometheus histograms (mockforge_chaos_jitter_ms, mockforge_chaos_bandwidth_throttle_ms{direction}). ChaosStatsSnapshot gains mean latency, jitter samples + mean offset, and bandwidth-throttle totals. TUI Chaos Fault Stats panel renders all of them.
  • [Reality] Bench client surfaces server-injected chaos signals (#79 item 7)
    • HTTP chaos middleware stamps X-Mockforge-Injected-Latency-Ms, -Injected-Jitter-Ms, and -Fault response headers. Generated k6 script reads them into custom trends (mockforge_server_injected_latency_ms, mockforge_server_injected_jitter_ms) and a counter (mockforge_server_fault_total). Bench summary prints a new Server-Injected (chaos) block alongside client-observed latency.
  • [DevX] New bench CLI flags --rps and --cps (#79 item 8)
    • --rps N switches the k6 executor from ramping-vus to constant-arrival-rate at N requests/sec (and drops the per-iteration sleep(1) that previously capped throughput at ~2 RPS). --cps sets noConnectionReuse: true so each request opens a fresh TCP/TLS connection — useful for stressing connection-limit chaos and TCP-level fault injection.
  • [Reality] Opt-in MOCKFORGE_HTTP_KEEPALIVE_HINT=1 advertises Connection: keep-alive + Keep-Alive: timeout=N, max=M on every response (#79 item 2 workaround)
    • For proxies (F5/Avi/HAProxy/nginx) that read those headers when deciding to pool upstream sockets. Best-effort signal; the actual fix for the FIN-after-response pattern is upstream HTTP/1.1 negotiation in the proxy itself.

[0.3.131] - 2026-05-10

Added

  • [Reality] TUI Chaos screen now surfaces live fault-injection counts (#79 follow-up)
    • New ChaosStatsSnapshot and GET /api/chaos/stats (+ admin passthrough at /__mockforge/chaos/stats).
    • Fault Stats panel below Settings shows totals + per-fault-type counts. Older servers without the endpoint fall back to the 2-panel layout.

[0.3.130] - 2026-05-10

Fixed

  • [Reality] mockforge_chaos_* counters silently absent from /metrics (#79 follow-up)
    • Chaos counters register against the global prometheus::default_registry(); /metrics was exporting only the local MetricsRegistry. The two were disjoint, so chaos counters never surfaced. metrics_handler now gathers from both. No format change for scrapers.
  • [Reality] LatencyInjectionConfig / RateLimitingConfig / NetworkShapingConfig rejected partial YAML
    • Missing fields broke the whole config load (e.g. traffic_shaping: without max_connections). Adding Default + #[serde(default)] makes partial YAML parse cleanly.

[0.3.129] - 2026-05-09

Added

  • [Reality] YAML config now exposes every chaos fault_injection field (#79 follow-up)
    • mockforge_core::config::FaultConfig gains connection_error_kind, partial_responses + partial_response_probability, payload_corruption + payload_corruption_probability, corruption_type, error_pattern (Burst / Random / Sequential), mockai_enabled, and request_matcher. All #[serde(default)] so existing chaos.yaml files keep parsing.
    • The bridge in serve.rs now maps every field through to mockforge_chaos::config::FaultInjectionConfig; previously these were silently defaulted at YAML load time and only the PUT /api/chaos/config/faults REST API could set them.

[0.3.128] - 2026-05-09

Fixed

  • [DevX] k6 metric-name validation failure on deeply nested OpenAPI specs (Microsoft Graph etc.) (#436, #79)
    • Root cause: operationIds like drives.drive.items.driveItem.workbook.worksheets.workbookWorksheet.charts.workbookChart.axes.categoryAxis.format.line.clear, after dot-to-underscore sanitization plus _latency / _errors suffix, exceeded k6’s 128-char metric-name cap. validate_script correctly rejected the script before k6 ran.
    • New K6ScriptGenerator::sanitize_k6_metric_name caps the base at 112 chars (128 − 16 for _step99_latency) and appends an 8-hex-char hash of the original name when truncating, so distinct long names produce distinct metric names. JS variable identifiers keep the full readable form; only the metric string is truncated.
    • Wired into both render paths: k6_script.hbs (per-operation) and k6_crud_flow.hbs. Tests cover passthrough, truncation, prefix-collision uniqueness, the “starts with letter or _” rule after truncation, and end-to-end script validation on a microsoft-graph-style operationId.
  • [Reality] Chaos prometheus counters were registered but never incremented (#436, #79)
    • mockforge_chaos_faults_total{fault_type, endpoint}, mockforge_chaos_latency_ms, and mockforge_chaos_rate_limit_violations_total all existed in the registry, but no caller invoked the corresponding record_* methods. /metrics reported zero faults regardless of how many were actually firing — masking the effect of configured chaos rules from operators.
    • Wired record_fault(...) at every fault decision point in the HTTP middleware (http_error, timeout, rate_limit, connection_limit, packet_loss, partial_response, payload_corruption) and the TCP chaos listener (tcp_reset, tcp_close). Latency injection also now records to the histogram via record_latency.
    • The TUI Chaos screen still renders config-only; surfacing these counters as a stats panel is tracked as a follow-up.

[0.3.127] - 2026-05-08

Fixed

  • [Reality] TPS / RPS200 dashboard counters stuck at 0 under load (#351, #79)
    • Metrics middleware (collect_http_metrics) was never .layer()d on the production router built in serve.rs. CPS still advanced because CountingMakeService wraps the make-service at a different layer.
    • Layer collect_http_metrics as the outermost wrapper on http_app so every response — including chaos-mutated ones — bumps the rate counters the dashboard sampler reads.

Added

  • [DevX] bench-chunked accepts --base-path, humantime --duration, --validate-requests, --export-requests (#352, #79)
    • --base-path <PATH> prepends to every spec-derived operation path before URL construction. CLI > spec.servers > none.
    • -d 600s / --duration <DURATION> switched from bare seconds (u64) to humantime parsing.
    • --validate-requests and --export-requests mirror the flags already on mockforge bench.
  • [DevX] Supervisor wrappers for unattended runs under heavy traffic (#350, #79)
    • deploy/systemd/mockforge.service — systemd unit with Restart=always.
    • deploy/scripts/run-forever.sh — bash supervisor that restarts the binary after any non-clean exit.

[0.3.73] - 2026-03-05

Fixed

  • [UI] Fix cargo publish failure for mockforge-ui caused by build.rs modifying source directory
    • Removed code that copied pwa-manifest.json and sw.js into ui/dist/ during build (violates cargo’s source-dir-immutability rule)
    • serve_service_worker now reads sw.js from ui/public/ (same pattern as serve_manifest)
    • Added sw.js to the crate’s include list so it’s packaged correctly
  • [Core] Mock server now supports X-Mockforge-Response-Status header to return non-default status codes (#79)
    • Conformance checks for response:404 and response:400 previously always failed because the server returned the first declared status (usually 200)
    • New has_response_for_status() validates the requested code exists in the spec before overriding
    • Both OpenAPI handler paths extract and pass the header through
  • [Core] Response generation no longer replaces object-typed properties with string examples (#79)
    • When a property schema declares type: object, the fallback now preserves an empty {} instead of generating a name-based string like "example config"
    • Fixes response:schema:validation failures where JSON schema validation rejected string values for object properties
    • Added is_object_typed_property() helper for type-aware fallback decisions
  • [Data] generate_by_type("object") now returns {} instead of "unknown_type_object" (#79)
    • Also added "array" handler returning []

Changed

  • [Bench] Spec-driven conformance generator now sends X-Mockforge-Response-Status header for response:400 and response:404 checks (#79)
    • Tells the mock server which status code to return, enabling accurate status-code conformance testing

[0.3.72] - 2026-03-04

Fixed

  • [UI] mockforge serve --admin no longer panics when no production auth is configured (#79)
    • validate_auth_config_on_startup() now logs a warning instead of returning an error
    • Auto-generated JWT secret fallback so the admin UI works out of the box
    • Default users are seeded even without ENVIRONMENT=development, so login works immediately
  • [Bench] Fix duplicate session ID in conformance Cookie headers (#79)
    • Removed invalid noCookies: true from k6 options (not a real k6 option; k6 silently ignores it)
    • Added http.cookieJar().clear(BASE_URL) before and after each request when custom Cookie headers are present
    • Prevents k6’s internal cookie jar from re-sending server Set-Cookie values alongside custom headers
    • Applied to both reference-mode (generator.rs) and spec-driven (spec_driven.rs) generators
  • [Bench] Fix missing single-quote escaping in spec-driven format_headers() (#79)
    • Header values containing single quotes are now properly escaped, matching generator.rs behavior

Added

  • [Bench] Conformance report now shows individual failed checks with pass/fail counts (#79)
    • New “Failed Checks” section after the category summary table lists each check that failed
    • When not using --conformance-all-operations, prints a tip suggesting it for endpoint-level detail

[0.3.70] - 2026-02-27

Fixed

  • [Bench] Remove dead CUSTOM_HEADERS JS const from conformance generators (#79)
    • Custom header values are now inlined directly into each request instead of referencing an unused JS constant
    • Eliminates confusing dead code in generated k6 scripts
  • [Bench] Add noCookies: true to k6 options when Cookie header is in custom headers (#79)
    • Prevents k6’s automatic cookie jar from duplicating cookies on subsequent requests
    • Fixes duplicate session ID / authentication failures reported by @srikr
  • [Bench] Fix conformance report file not found after k6 execution (#79)
    • handleSummary now writes conformance-report.json to an absolute path matching the output directory
    • Previously wrote to a relative path based on k6’s CWD, causing the CLI to report “Conformance report not generated”

Added

  • [Bench] --conformance-all-operations flag for full-endpoint conformance testing (#79)
    • Default mode tests one representative operation per feature check (fast feature-coverage)
    • New flag tests ALL operations with path-qualified check names (e.g., method:GET:/api/users)
    • Addresses user confusion about “only 5 endpoints tested”
  • [Bench] Conformance coverage summary output (#79)
    • After generating conformance tests, prints “Conformance: N operations analyzed, M unique checks generated”
    • When using default mode with fewer checks than operations, shows tip about --conformance-all-operations

[0.3.69] - 2026-02-24

Fixed

  • [Multi] Replace 36+ assert!(true) placeholder tests with meaningful assertions across 16 files
    • CLI command tests (MQTT, SMTP, governance) now construct and verify command variants
    • Registry server tests use compile-time type checks instead of no-op assertions
    • Integration tests (voice workspace, drift GitOps, behavioral cloning, WebSocket, cross-platform sync) use proper verification patterns
  • [gRPC] Add use super::* to 13 empty test_module_compiles() tests so they actually verify module compilation
  • [HTTP] Fix misleading “placeholder” doc comment on fully-implemented get_proxy_inspect handler

[0.3.57] - 2026-02-14

Fixed

  • [Bench] Spec-driven conformance: global security requirement detection (#79)
    • annotate_security() now falls back to spec.security (root-level) when an operation has no operation-level security defined
    • APIs that only define security globally are now correctly detected
  • [Bench] Spec-driven conformance: SecurityScheme type resolution (#79)
    • Security schemes are now resolved from components.securitySchemes to detect actual type (HTTP/bearer, APIKey, HTTP/basic) instead of relying on name heuristics alone
    • A scheme named “myAuth” that is actually an apiKey type is now correctly identified
    • Name-based heuristic retained as fallback for unresolvable schemes
  • [Bench] Spec-driven conformance: ContentNegotiation detection (#79)
    • ContentNegotiation feature is now detected when a response defines multiple content types (e.g., both application/json and application/xml)
    • Previously only worked in reference mode
  • [Bench] CLI help text for --conformance-categories now includes response-validation (#79)

Added

  • [Bench] 5 new conformance tests: ResponseValidation with schema check, global security, SecurityScheme resolution, ContentNegotiation detection, single-type negative case (#79)

[0.3.56] - 2026-02-14

Added

  • [Bench] Conformance category filtering (#79)
    • New --conformance-categories flag to run only specific conformance categories (e.g., --conformance-categories "parameters,security")
    • Case-insensitive category matching with validation against known categories
  • [Bench] Spec-driven conformance testing (#79)
    • When --conformance --spec my-api.json is provided, analyzes the user’s actual OpenAPI spec to detect which features their API exercises
    • Generates conformance tests against real endpoints instead of reference /conformance/ paths
    • Full $ref resolution with cycle detection for parameters, schemas, request bodies, and responses
    • Detects: parameter types, request body formats, schema types/composition/formats/constraints, response codes, security schemes
  • [Bench] Response schema validation (#79)
    • In spec-driven mode, validates response bodies against OpenAPI response schemas
    • SchemaValidatorGenerator produces JavaScript validation expressions from OpenAPI schemas
    • Supports object (required fields, property types), array, string (format regex, enum, length), integer/number (range), boolean validation
    • Wrapped in try-catch for resilient k6 execution
  • [Bench] SARIF 2.1.0 report output (#79)
    • New --conformance-report-format sarif flag outputs conformance results in SARIF 2.1.0 format
    • Compatible with GitHub Code Scanning, VS Code SARIF Viewer, and CI/CD pipelines
    • Maps each conformance feature to a SARIF rule with OpenAPI spec section links
    • Passed features emit level: "note", failed features emit level: "error"

[0.3.55] - 2026-02-14

Added

  • [Bench] Per-server stats in multi-target mode (#79)
    • K6Results now parses RPS, VUs, and full latency breakdown (min/med/p90/p95/p99/max) from k6 summary.json
    • AggregatedMetrics includes total_rps, avg_rps, total_vus_max
    • Multi-target reporter shows per-target RPS, VUs, and full latency breakdown
    • aggregated_summary.json includes all new metrics in both aggregated and per-target sections
  • [Bench] Per-target spec support for multi-target mode (#79)
    • Targets file JSON format now supports "spec" field for per-target OpenAPI specs
    • Each target can use a different spec file for heterogeneous fan-out
    • Example: [{"url": "https://server1", "spec": "spec_a.json"}, {"url": "https://server2", "spec": "spec_b.json"}]
  • [Bench] OpenAPI 3.0.0 conformance testing (#79)
    • New --conformance flag generates and runs comprehensive k6 scripts exercising 47 OpenAPI 3.0.0 features across 10 categories (Parameters, Request Bodies, Schema Types, Composition, String Formats, Constraints, Response Codes, HTTP Methods, Content Negotiation, Security)
    • Reports per-category pass/fail rates with colored terminal output
    • Supports --conformance-api-key, --conformance-basic-auth, --conformance-report for security scheme testing
    • Example: mockforge bench --conformance --target http://localhost:3000

[0.3.54] - 2026-02-13

Fixed

  • [Bench] fix(bench): deliver CRS payloads as path injection + form-encoded body (#79)
    • Added inject_as_path field to SecurityPayload — URI payloads without query params (e.g., CRS 942101: POST /1234%20OR%201=1) now replace the request path via encodeURI() so WAFs inspect REQUEST_FILENAME instead of ARGS
    • Added form_encoded_body field to SecurityPayload — body payloads from CRS tests (e.g., 942432: var=;;dd foo bar) now sent as application/x-www-form-urlencoded so WAFs parse form data into ARGS for character counting
    • Updated k6_script.hbs and k6_crud_flow.hbs templates to handle both new delivery mechanisms
    • Replaced unreliable startsWith('/') URI heuristic in CRUD flow template with explicit injectAsPath flag
    • Expected SQLi detection: 46/46 rules (100%), up from 45/46 (97.8%)

[0.3.53] - 2026-02-13

Fixed

  • [Bench] fix(bench): URL-encode URI payloads + strip form keys from body payloads (#79)
    • URI security payloads now wrapped in encodeURIComponent() for valid HTTP transport — WAFs decode before inspection (fixes 942101)
    • Form-encoded body payloads now have form key prefix stripped (var=;;dd foo bar → ;;dd foo bar) so WAF ARGS parsing sees the attack payload directly (fixes 942432)
    • Confirmed SQLi detection: 45/46 rules (97.8%), up from 43/46 (93.5%)

[0.3.52] - 2026-02-12

Fixed

  • [Bench] fix(bench): Group multi-part WAFBench payloads + decode body payloads + fix Cookie/CookieJar conflict (#79)
    • Multi-part CRS test cases (URI + headers + body) now grouped by group_id and sent together in one HTTP request instead of being split across separate requests (fixes 942290)
    • Body payloads from CRS YAML files are now form-URL-decoded before injection (%22+WAITFOR+DELAY+%27 → " WAITFOR DELAY ') so WAFs see actual SQL patterns in JSON bodies (fixes 942240, 942320, 942432)
    • URI payloads from path-only CRS tests are now URL-decoded and stripped of leading / artifact (fixes 942101)
    • Cookie header payloads no longer overridden by empty CookieJar — secRequestOpts conditionally skips jar: new http.CookieJar() when a security Cookie header is present (fixes 942420, 942421)
    • Added groupedPayloads array-of-arrays in generated k6 scripts; getNextSecurityPayload() returns arrays of related payloads
    • Template loop applies URI/header/body parts simultaneously per request via secPayloadGroup
    • Expected SQLi detection improvement: 37/46 → 44/46 (80.4% → 95.7%)

[0.3.51] - 2026-02-11

Fixed

  • [Bench] fix(bench): Accept all WAFBench CRS payloads without attack-pattern filter (#79)
    • Removed overly strict attack-pattern category filter that was silently dropping valid CRS test cases
    • All CRS YAML test cases now loaded regardless of their attack_type metadata

[0.3.50] - 2026-02-10

Fixed

  • [Bench] fix(bench): Use per-request CookieJar instead of shared EMPTY_JAR (#79)
    • Each HTTP request now creates its own new http.CookieJar() instead of sharing a global empty jar
    • Prevents cookie cross-contamination between requests in security testing

[0.3.49] - 2026-02-09

Fixed

  • [Bench] fix(bench): Send raw security payloads + use dedicated empty cookie jar (#79)
    • Security payloads now sent as raw strings without additional encoding
    • Dedicated empty CookieJar per request prevents k6’s default cookie accumulation

[0.3.48] - 2026-02-08

Fixed

  • [Bench] fix(bench): Cycle security payloads per-operation + clear cookies in API2 tests (#79)
    • Security payloads now cycle per-operation block (each API endpoint gets a different payload)
    • Previously all operations in one VU iteration used the same payload
    • OWASP API2 (Broken Auth) tests now properly clear cookies between requests

[0.3.47] - 2026-02-06

Added

  • [DevX] chore: Add Claude Code setup (CLAUDE.md, agents, skills, hooks, hookify)
    • Project-specific Claude Code configuration with rules, agents, and skills
    • Custom skills for verification, template checking, code review, and bench review
    • Hookify rules engine for behavioral guardrails

Fixed

  • [Bench] fix(bench): Security payloads now injected + cookie dedup in all templates (#79)

    • Security payloads now properly injected in both k6_script.hbs and k6_crud_flow.hbs templates
    • Cookie deduplication applied to all HTTP request paths in both templates
    • Comprehensive test suite added for issue #79 security pipeline
  • [Registry] fix(registry): Add RBAC permission system with Display, AdminAll bypass, and PermissionChecker

    • New RBAC permission model with role-based access control
    • AdminAll role bypasses all permission checks
    • PermissionChecker trait for consistent authorization across endpoints

[0.3.46] - 2026-01-30

Fixed

  • [Bench] fix(bench): WAFBench payloads now distributed across VUs for better coverage (#79)

    • Changed payload cycling to use VU-based offset: (__VU - 1) % payloads.length
    • Previously all 50 VUs started at index 0 and cycled through same sequence
    • Now each VU starts at a different payload, maximizing attack coverage in shorter test runs
    • With 50 VUs and 30 payloads, all payloads are tested from the start
  • [Bench] fix(bench): OWASP API tests now include custom headers in all requests (#79)

    • Added CUSTOM_HEADERS to API8 verbose error test (malformed JSON body test)
    • Added CUSTOM_HEADERS to API9 discovery paths test
    • Added CUSTOM_HEADERS to API9 API versions test
    • Fixes auth failures when using --headers "Cookie:..." with OWASP testing

[0.3.43] - 2026-01-16

Fixed

  • [Bench] fix(bench): Security payloads now actually applied to requests in k6 scripts (#79)
    • Updated k6_script.hbs template to call getNextSecurityPayload() and applySecurityPayload()
    • Previously, security payload functions were defined but never called in generated scripts
    • Security payloads now properly injected into request bodies for POST/PUT/PATCH
    • Header-based payloads now properly injected into request headers

[0.3.42] - 2026-01-15

Fixed

  • [Bench] fix(bench): XSS payloads now inject into ALL string fields, not just the first one (#79)
    • Removed break statement from applySecurityPayload() loop in security_payloads.rs
    • Ensures WAF can detect payloads regardless of which field it scans
  • [Bench] fix(bench): Added jar: null to remaining OWASP HTTP calls to prevent cookie duplication (#79)
    • Fixed testBrokenAuth empty token test
    • Fixed testMisconfiguration verbose error test
    • Fixed testInventory discovery paths and API versions checks
  • [CLI] fix(cli): Fixed format string compilation error in plugin_commands.rs (#79)
    • Escaped all braces ({ → {{, } → }}) inside format! macro for auth plugin template
    • Fixes “invalid format string: expected }, found r” compilation error

[0.3.39] - 2026-01-14

Fixed

  • [Bench] fix(bench): WAFBench XSS attacks now properly injected into request body (#79)
    • Removed location check from applySecurityPayload() - ALL payloads now injected into body for POST/PUT
    • WAFBench payloads correctly pass location info (uri/header/body) to k6 scripts
    • Header payloads include header name for proper injection into specified headers
  • [Bench] fix(bench): Cookie header duplication in OWASP and security tests (#79)
    • Added jar: null to all HTTP request params to disable k6’s automatic cookie jar
    • Prevents duplicate cookies when user provides Cookie header via --headers flag
    • Applied to k6_script.hbs, k6_crud_flow.hbs, and OWASP generator

[0.3.38] - 2026-01-13

Fixed

  • [Bench] fix(bench): pass custom headers from --headers flag to OWASP tests (#79)
    • Cookie and other custom headers are now included in all OWASP request helpers
    • Fixes issue where avi-sessionid=None was being sent instead of actual cookie values
  • [Bench] fix(bench): WAFBench loader now handles single YAML file paths (#79)
    • Previously only directories or glob patterns were supported
    • Single file paths like /path/to/941100.yaml now work correctly
  • [Bench] Verified CRS v3.3 format compatibility with full CoreRuleSet test suite
    • Tested with 175 files, 1512 payloads (692 XSS, 505 SQLi, 304 Command Injection, 11 Path Traversal)

[0.3.37] - 2026-01-12

Added

  • [Bench] feat(bench): add WAFBench cycle-all mode (--wafbench-cycle-all) to test all payloads sequentially (#79)
  • [Bench] feat(bench): add --owasp-iterations parameter to control OWASP test iterations per VU (#79)
  • [Bench] feat(bench): OWASP tests now respect --vus parameter for concurrent testing (#79)

Fixed

  • [Bench] fix(bench): WAFBench payloads now properly injected in standard bench mode (not just CRUD flow)
  • [Bench] fix(bench): OWASP APIs now use random UUIDs per request instead of static IDs for BOLA testing (#79)
  • [Bench] fix(bench): OWASP auth tokens with special characters (quotes, backslashes) now properly escaped (#79)
  • [Bench] fix(bench): prevent Handlebars double-escaping of pre-escaped JavaScript values
  • [Bench] fix(bench): WAFBench security payloads now integrated into CRUD flow requests (#79)
  • [Bench] fix(owasp): use http.del() instead of http.delete() for k6 compatibility (#79)
  • [Bench] fix(owasp): add --base-path support for OWASP API testing (#79)
  • [Bench] fix(bench): remove undefined totalRequestCount variable reference
  • [Bench] fix(bench): support CRS v3.3 WAFBench format and pass --insecure to OWASP tests

[0.3.33] - 2026-01-10

Fixed

  • [Bench] fix(bench): multiple fixes for OWASP and WAFBench testing
    • Support CRS v3.3 format in WAFBench parser
    • Pass --insecure flag to OWASP tests for self-signed certificates

[0.3.31] - 2026-01-08

Fixed

  • [Bench] fix(bench): fix extracted value substitution in CRUD flows
  • [Bench] fix(bench): OWASP k6 configuration improvements

[0.3.30] - 2026-01-07

Added

  • [Bench] feat(bench): add merge_body support for CRUD flows - merge extracted values with request body
  • [Bench] feat(bench): add inject_attacks data model for security testing in CRUD flows

[0.3.28] - 2026-01-06

Added

  • [Bench] feat(bench): add nested path extraction for CRUD flows (e.g., results[0].id)
  • [Bench] feat(bench): add filter extraction for CRUD flows (e.g., results[?name=='test'].id)

[0.3.27] - 2026-01-05

Added

  • [Bench] feat(bench): add full body extraction for CRUD flows
  • [Bench] feat(bench): add key filtering for extracted values

[0.3.26] - 2026-01-04

Added

  • [Bench] feat(bench): add aliased extraction for CRUD flow value chaining
    • Extract values with aliases (e.g., id as poolId) for use in subsequent requests

[0.3.24] - 2026-01-03

Fixed

  • [Bench] fix(bench): use correct variable name in CRUD flow extracted value replacement

[0.3.22] - 2026-01-02

Added

  • [Bench] feat(bench): add OWASP API Security Top 10 testing mode (#79)
    • Test for BOLA (API1), Broken Auth (API2), Mass Assignment (API3), Resource Consumption (API4)
    • Test for Function Auth (API5), SSRF (API7), Misconfiguration (API8), Inventory (API9), Unsafe Consumption (API10)
    • Configurable test categories with --owasp-categories
    • Support for auth tokens with --owasp-auth-token
    • SARIF and JSON report formats

Changed

  • [DevX] chore: include UI dist files for publishing to crates.io

[0.3.21] - 2025-12-31

Fixed

  • [DevX] fix(bench): use custom flow config and fix sequential mode path matching - enables cross-resource dependency chains
  • [DevX] fix(bench): process dynamic placeholders in CRUD flow params file bodies (#79)
  • chore: update benchmark baseline [skip ci]
  • chore: enable publishing for previously internal crates
  • chore: update benchmark baseline [skip ci]
  • fix(release): disable sccache for crates.io publish
  • chore: update benchmark baseline [skip ci]
  • fix(release): publish all crates in dependency order
  • fix(release): add mockforge-core to crates.io publish order
  • chore: update benchmark baseline [skip ci]
  • feat(bench): add –base-path option for API base path support (#79)
  • chore: update benchmark baseline [skip ci]
  • fix(collab): include SQLx query cache for crates.io installation (#79)
  • chore: update benchmark baseline [skip ci]
  • feat: implement optional enhancements from improvement plan
  • fix: update doc tests to use rust,ignore for external dependencies
  • chore: update benchmark baseline [skip ci]
  • chore: add missing crates to workspace and restore path dependencies
  • chore: restore path dependencies after publishing remaining v0.3.17 crates
  • fix: restore all crates to workspace members list
  • chore: restore path dependencies after publishing v0.3.17
  • docs: update CHANGELOG for v0.3.17 release
  • feat(bench): add WAFBench YAML integration for security testing
  • Bump version to 0.3.17
  • feat: comprehensive improvements across AMQP, MQTT, gRPC, registry server, and UI
  • feat(ui): add type safety, mobile layout fixes, and search/filter to frontend
  • Restore path dependencies after publishing v0.3.16
  • Bump version to 0.3.16
  • fix: resolve flaky tests and race conditions across test suite
  • fix: replace panic-prone unwrap calls with safe error handling
  • fix: resolve UUID storage format mismatch in collab crate tests
  • Add multi-spec support and cross-spec dependency detection for bench command
  • feat: add multi-spec support and cross-spec dependency handling to bench command
  • fix: add validation to CRUD flow script generation
  • fix: sanitize k6 CRUD flow metric names (#79 follow-up)
  • Bump version to 0.3.13 and improve changelog
  • Bump version to 0.3.12 and publish to crates.io
  • Bump version to 0.3.11 and publish to crates.io
  • chore: update benchmark baseline [skip ci]
  • feat: add –params-file option for custom parameter values in bench
  • Bump version to 0.3.10 and publish to crates.io
  • chore: update benchmark baseline [skip ci]
  • fix: move insecureSkipTLSVerify to global k6 options (fixes –insecure)
  • chore: update benchmark baseline [skip ci]
  • fix: resolve k6 bench issues with –insecure flag, textSummary, and query params
  • chore: update benchmark baseline [skip ci]
  • chore: bump version to 0.3.9 and update changelog
  • feat: implement comprehensive mock server functionality across all crates
  • chore: commit remaining version updates
  • fix: enable publishing for mockforge-ui
  • fix: enable publishing for mockforge-tunnel
  • fix: update all 0.3.7 dependencies to 0.3.8 with path dependencies
  • fix: add path dependencies for all workspace crates
  • chore: update CHANGELOG date for 0.3.8
  • chore: bump version to 0.3.8
  • Fix cargo publish issues: add version requirements to dependencies
  • chore: update benchmark baseline [skip ci]
  • Apply formatting and additional code changes
  • Fix compilation errors: update dependencies and adapt to API changes
  • fix: remove path from mockforge-pipelines dep in mockforge-collab
  • Add mockforge-sdk, mockforge-ui, mockforge-cli to workspace
  • fix: add mockforge to restore function targets list
  • fix: convert mockforge dev-dependencies to path dependencies
  • fix: add mockforge-core to restore list and manually fix dependency
  • fix: include mockforge-core in restore list
  • fix: restore function now properly handles table-form dependencies without path
  • fix: automatically restore dependencies at start of publish
  • fix: restore all crate dependencies, not just a few
  • fix: only convert dependencies for already-published crates
  • fix: correct publish order - publish mockforge-data before mockforge-core
  • fix: add mockforge-data as optional dependency in mockforge-core
  • chore: bump version to 0.3.6 and update changelog
  • chore: update benchmark baseline [skip ci]
  • Fix k6 script generation and UI icon embedding issues
  • chore: update benchmark baseline [skip ci]
  • Add comprehensive test suite and fix build issues
  • chore: update benchmark baseline [skip ci]
  • docs: add comprehensive performance benchmarks documentation
  • chore: update benchmark baseline [skip ci]
  • fix: implement real functionality in benchmark tests and fix k8s-operator
  • chore: update benchmark baseline [skip ci]
  • fix: filter out ‘change’ directories from benchmark baseline parsing
  • chore: update benchmark baseline [skip ci]
  • chore: update benchmark baseline [skip ci]
  • fix: GitHub Actions workflow cleanup and fixes (#81)
  • chore: restore dependencies after publishing all crates
  • fix: add mockforge-cli to workspace and add metadata to mockforge-k8s-operator
  • fix: add missing crates to workspace (mockforge-sdk, mockforge-http, mockforge-ui, mockforge-k8s-operator)
  • fix: add mockforge-world-state to workspace and publishing order before mockforge-http
  • fix: add mockforge-route-chaos publishing step before mockforge-http
  • fix: add mockforge-route-chaos to dependency targets and publishing order
  • fix: add mockforge-route-chaos to workspace and publishing script
  • fix: add mockforge-route-chaos to publishing order before mockforge-http
  • fix: reduce keywords from 6 to 5 for mockforge-performance
  • fix: reduce keywords to 5 for mockforge-performance (crates.io limit)
  • fix: add mockforge-performance to publishing order before mockforge-http
  • fix: add mockforge-collab to workspace members list
  • fix: add mockforge-collab to workspace members
  • fix: add missing README.md for mockforge-pipelines
  • fix: add mockforge-pipelines to publishing order and dependency targets
  • fix: add mockforge-pipelines to workspace and publishing script
  • fix: add all missing crates to workspace members
  • fix: handle short form dependencies when converting to path
  • fix: publish mockforge-template-expansion before mockforge-core
  • fix: add mockforge-template-expansion to publishing script
  • fix: temporarily convert dependent crates’ dependencies to path before publishing
  • fix: remove argon2 from mockforge-core during MSRV checks
  • fix: exclude mockforge-collab from MSRV checks and remove patch section
  • fix: use awk instead of sed for multi-line patch section insertion
  • fix: use Cargo patch section to pin base64ct for MSRV
  • fix: improve base64ct pinning order in MSRV workflow
  • fix: use exact version constraint for base64ct in MSRV workflow
  • fix: improve base64ct pinning in MSRV workflow
  • fix: pin base64ct to 1.7 for MSRV compatibility
  • fix: exclude mockforge-ui from MSRV checks
  • fix: add abd and existant to typos config
  • fix: exclude FontAwesome and all minified files from spell check
  • fix: also remove sysinfo from mockforge-ui during MSRV checks
  • fix: exclude elasticlunr.min.js from spell check
  • fix: exclude highlight.js from spell check
  • fix: disable sysinfo feature during MSRV checks
  • fix: sync sysinfo to 0.37, fix resolvable typo, exclude ace.js from spell check
  • fix: pin sysinfo to 0.36, fix typos, improve MSRV workaround
  • fix: update MSRV to 1.80 and add GraphQL exclusion workaround
  • fix: update MSRV from 1.82 to 1.75
  • fix: fix GitHub Actions workflow failures
  • fix: standardize dependencies and fix all test failures
  • Skip CRDs in kubectl validation to avoid server connection
  • Fix kubectl validation to prevent server connection attempts
  • Fix kubectl validation to skip server connection
  • Fix all test failures and resolve dependency conflicts
  • Fix k6 metric name validation error (issue #79) (#80)
  • Optimize workflows: update deprecated actions and add path filters
  • Fix mockforge-smtp version constraint from 0.2.0 to 0.3.3
  • Fix Docker build, k8s validation, and spell check issues
  • fix: update all mockforge dependency versions to 0.3.3 in mockforge-http
  • chore: fix formatting (pre-commit hooks)
  • deps(deps): bump opentelemetry_sdk from 0.21.2 to 0.31.0 (#67)
  • chore: update benchmark baseline [skip ci]
  • deps(deps): bump opentelemetry-semantic-conventions (#66)
  • chore: update benchmark baseline [skip ci]
  • deps(deps): bump sysinfo from 0.32.1 to 0.37.2 (#60)
  • deps(deps): bump wasmparser from 0.239.0 to 0.240.0 (#64)
  • deps(deps): bump governor from 0.6.3 to 0.8.1 (#61)
  • chore: update benchmark baseline [skip ci]
  • deps(deps): bump mail-parser from 0.9.4 to 0.11.1 (#63)
  • deps(deps): bump rumqttc from 0.24.0 to 0.25.0 (#65)
  • deps(deps): bump ndarray from 0.16.1 to 0.17.1 (#76)
  • chore: update benchmark baseline [skip ci]
  • ci(deps): bump azure/setup-helm from 3 to 4 (#72)
  • ci(deps): bump actions/upload-artifact from 4 to 5 (#71)
  • deps(deps): bump image from 0.24.9 to 0.25.9 (#77)
  • deps(deps): bump rustls from 0.21.12 to 0.23.35 (#78)
  • chore: update benchmark baseline [skip ci]
  • Bump all crates to version 0.3.3
  • Format code with rustfmt
  • Fix k6 script generation with operation IDs containing dots/hyphens
  • chore: update benchmark baseline [skip ci]
  • perf: optimize template rendering by avoiding unnecessary operations
  • chore: update benchmark baseline [skip ci]
  • docs: update benchmark documentation with final optimizations
  • perf: fix benchmark regressions and optimize measurements
  • chore: update benchmark baseline [skip ci]
  • Fix Kafka compilation errors and borrow checker issues
  • feat: Implement cross-pillar enhancements - World State Engine, MOD, and Performance Mode
  • feat(ai-studio): Add API Critique, System Generator, and Behavioral Simulator
  • chore: rework UI/UX to be more AI native
  • fix: Address pre-commit security vulnerabilities
  • feat: Implement Invisible Mock Server experience (DevX Pillar)
  • feat(security): implement email, Slack, and webhook notification services
  • Refactor template expansion for Send safety
  • chore: Restore path dependencies after 0.3.2 publish
  • Fix: Complete SQLx query cache for mockforge-collab 0.3.2
  • chore: update mockforge dependencies to version 0.3.1 across multiple crates
  • fix: improve dependency conversion for optional dependencies and fix publishing order
  • fix: update publish script to handle Phase 1 crate dependencies correctly
  • feat: add comprehensive integration tests for 0.3.0 features and update changelog
  • feat: Complete pillar enhancement gaps - VS Code extension and docs
  • feat: Implement pillar tagging system and documentation enhancements
  • feat: Implement MockForge AI Studio - Unified AI Copilot
  • feat(cloud): Complete Cloud pillar implementation and fix compilation issues
  • [DevX] Add JSON Schema support for config validation and IDE autocompletion
  • feat: Implement Contract Fitness Functions, Consumer Impact Analysis, and Multi-Protocol Contracts
  • feat: Enhance Reality feature with observability, cross-protocol consistency, and time-aware lifecycles
  • fix: use proper vosk API by matching on CompleteResult enum
  • fix: resolve all compilation errors
  • chore: prepare release 0.3.0
  • feat: Implement LLM Studio - Natural Language Workspace Creation (0.3.4)
  • feat: Complete Behavioral Cloning v1 implementation and refactor architecture
  • feat: Implement Drift Budget & GitOps for API Sync + AI Contract Diff
  • feat: implement Scenario Studio Visual Editor with React Flow
  • feat: implement AI-Native Interface Deepening features
  • feat: Implement Time Travel & Snapshots and Frontend X-Ray Mode
  • feat(sdk): Add Contract-Backed Types and Scenario-First SDKs to Vue, Svelte, and Angular
  • Format code: Apply rustfmt and whitespace cleanup
  • Release v0.2.9: Update version, CHANGELOG, and publish all crates to crates.io
  • Add registry server improvements, password reset, metrics, and marketplace enhancements
  • security: Upgrade wasmtime to 36.0.3 to fix RUSTSEC-2025-0118
  • feat: Fix compilation errors and implement comprehensive E2E test suite
  • fix: implement custom routes, template expansion, latency injection, and init improvements
  • feat: Smart Personas with array generation and relationship inference
  • feat: Complete Java and .NET SDK implementations with builder patterns
  • fix: update all test files for new function signatures
  • fix: resolve all compilation errors across workspace
  • Complete Phase 3 security controls implementation
  • Add cloud monetization infrastructure and features
  • Implement organization management endpoints
  • Fix Axum 0.8 route syntax in state_machine_api.rs
  • Fix file server route syntax for Axum 0.8 compatibility
  • Release v0.2.8: Publish all crates to crates.io
  • chore: bump version to 0.2.8
  • feat: Complete Generative Schema Mode and achieve 100% roadmap completion
  • Implement Smart Personas feature for consistent cross-endpoint data generation
  • Add Reality Continuum feature for blending mock and real data sources
  • Implement Voice + LLM Interface with STT backends
  • Implement complete Deceptive Deploy feature
  • Add GraphQL + REST Playground with workspace filtering
  • Implement ForgeConnect SDK with full feature set
  • Add enhanced scenario marketplace features
  • Configure SQLx and integrate mockforge-collab with mockforge-core
  • Fix test compilation errors in reality integration and hot-reload tests
  • Implement Reality Slider feature with hot-reload support
  • Complete latency recording integration and fix WorkspaceConfig reality_level field
  • style: Apply rustfmt formatting to Chaos Lab code
  • feat: Add Chaos Lab interactive network condition simulation
  • Fix test compilation errors in openapi_generator_tests
  • Fix all compilation errors for AI Contract Diff feature
  • Add WireMock-inspired features: browser proxy mode, git sync, data sources, template library, managed hosting docs, and user management
  • Add comprehensive ecosystem and use cases documentation
  • Complete configuration and extensibility implementation
  • Add advanced behavior and simulation features
  • Fix test and benchmark compilation errors
  • Complete Scenario State Machines 2.0 with sub-scenario execution
  • Implement VBR Engine enhancements: OpenAPI integration, M2M relationships, seeding, ID generation, snapshots
  • Add mock-to-real migration pipeline with per-route toggling
  • Add Data Scenarios Marketplace feature
  • feat: Implement ForgeConnect - Front-End Integrated Mode for browser-based mock creation
  • Add MockForge Cloud Graph visualization with real-time updates and export
  • Add data personality profiles system for consistent mock data generation
  • Add realistic network conditions and chaos lab with interactive UI controls
  • Add temporal simulation with CLI commands and scenario support
  • Complete MockAI implementation with query params and session recording
  • Add Virtual Backend Reality (VBR) engine
  • Add multipart form data support and file generation/serving for API mocks
  • fix: update mockforge-plugin-sdk to use workspace version
  • fix: enable publishing for mockforge-tunnel and add to publish script

[0.3.20] - 2025-12-31

Fixed

  • [Bench] Dynamic placeholder expansion in CRUD flow params file bodies (#79): Fixed ${__VU}, ${__ITER}, and other dynamic placeholders not being expanded when used in request body content from params files
    • Previously, placeholders like "name": "HTTP-WAAP-vsvip-${__VU}-${__ITER}" were sent literally to the API
    • Now properly converted to k6 template literals for runtime evaluation
    • Supports all dynamic placeholders: ${__VU}, ${__ITER}, ${__TIMESTAMP}, ${__UUID}, ${__RANDOM}, ${__COUNTER}, ${__DATE}, ${__VU_ITER}

[0.3.19] - 2025-12-30

Added

  • [DevX] API base path support for bench command (#79): New --base-path option to prepend a path prefix to all API endpoints in generated load tests
    • Automatically extracts base path from OpenAPI spec’s servers URL (e.g., https://api.example.com/api/v1 → /api/v1)
    • CLI option takes priority over spec’s base path for explicit control
    • Use --base-path "" to disable base path even if spec defines one
    • Works with both standard k6 scripts and CRUD flow mode
    • Example usage:
      # Auto-detect from spec's servers URL
      mockforge bench --spec api.yaml --target http://localhost:8080 --crud-flow
      
      # Explicitly set base path
      mockforge bench --spec api.yaml --target http://localhost:8080 --base-path /api
      
      # Disable base path
      mockforge bench --spec api.yaml --target http://localhost:8080 --base-path ""
      

[0.3.18] - 2025-12-29

Fixed

  • [Collab] SQLx offline mode for crates.io installation (#79): Fixed compilation errors when installing mockforge-collab from crates.io
    • Added .sqlx query cache directory with 51 precompiled query metadata files
    • The build.rs now automatically enables SQLX_OFFLINE=true when query cache is present
    • Users no longer need DATABASE_URL or to run cargo sqlx prepare to install the crate
    • Resolves “set DATABASE_URL to use query macros online” compilation errors

[0.3.17] - 2025-12-28

Added

  • [DevX] WAFBench YAML integration for security testing: New --wafbench-dir flag to import Microsoft WAFBench CRS (Core Rule Set) attack patterns

    • Parse WAFBench YAML test files from the WAFBench project
    • Support glob patterns for loading specific rule categories (e.g., REQUEST-941-* for XSS, REQUEST-942-* for SQLi)
    • Extract attack payloads from URI parameters, headers, and request bodies
    • Automatic CRS rule ID parsing from test metadata (e.g., 941100 for XSS attacks)
    • Integrate WAFBench payloads with existing security testing framework
    • Example usage:
      mockforge bench spec.yaml --wafbench-dir ./wafbench/REQUEST-941-*  # XSS rules
      mockforge bench spec.yaml --wafbench-dir ./wafbench/**/*.yaml      # All rules
      
  • [DevX] Per-URI control mode for data-driven testing (#79): New --per-uri-control flag for CSV/JSON data files that allows each row to specify HTTP method, URI, body, query params, headers, attack type, and expected status code

    • Enables fine-grained control over test requests directly from data files
    • Supports security testing per-URI with attack_type column
    • Automatic status validation with expected_status column
    • Example CSV format:
      method,uri,body,query_params,headers,attack_type,expected_status
      GET,/virtualservice,,include_name=true,,,200
      POST,/virtualservice,"{""name"":""test""}",,,sqli,201
      
  • [Protocol] AMQP TLS support: Full TLS/SSL support for AMQP broker with configurable certificates

  • [Protocol] MQTT protocol improvements: Enhanced MQTT server with TLS, session management, and metrics

  • [Protocol] gRPC dynamic service improvements: Better dynamic proto loading and error handling

  • [Registry] Security enhancements: CSRF protection, request ID middleware, trusted proxy support, token revocation

  • [UI] Frontend improvements: Type safety fixes, mobile layout improvements, search/filter functionality

Changed

  • Comprehensive dependency updates across workspace crates

Fixed

  • [DevX] CRUD flow params file integration (#79): Fixed --params-file not being applied in CRUD flow mode
    • Body configurations from params file are now correctly applied to POST/PUT/PATCH operations in --crud-flow mode
    • Fixed body serialization issue that caused “ReferenceError: object is not defined” error in generated k6 scripts
    • Body is now properly serialized as a JSON string for the Handlebars template
  • [Core] Race conditions and flaky tests: Resolved timing issues across test suite
  • [Core] Panic-prone unwrap calls: Replaced with safe error handling throughout codebase

[0.3.16] - 2025-12-27

Added

  • Version bump with dependency updates

Fixed

  • [Test] Flaky test fixes: Resolved race conditions and timing issues in integration tests
  • [Core] Safe error handling: Replaced panic-prone .unwrap() calls with proper error handling

[0.3.15] - 2025-12-26

Added

  • [DevX] Multi-spec support for bench command: The mockforge bench command now supports loading and merging multiple OpenAPI specifications
    • Multiple --spec flags: mockforge bench --spec pools.yaml --spec vs.yaml --target https://api.com
    • Directory discovery with --spec-dir: mockforge bench --spec-dir ./specs/ --target https://api.com
    • Conflict resolution strategies with --merge-conflicts: error (default), first, last
    • Spec mode selection with --spec-mode: merge (default) combines all specs, sequential runs specs in dependency order
    • Sequential execution mode with per-spec output directories and results
    • Leverages existing multi-spec infrastructure from mockforge-core
  • [DevX] Cross-spec dependency detection: New spec_dependencies module for handling dependencies between specs
    • Automatic detection of dependencies from field naming patterns (pool_ref, pool_id, poolId, etc.)
    • Schema registry for cross-referencing schemas across multiple specs
    • Topological sorting for correct execution order
    • Manual dependency configuration via --dependency-config (YAML/JSON)
    • Support for value extraction and injection between spec groups

Changed

  • BenchCommand.spec field changed from PathBuf to Vec<PathBuf> to support multiple specs
  • SpecParser now includes from_spec() method for pre-loaded OpenAPI specs
  • Added dependency_config field to BenchCommand for cross-spec value passing configuration

Fixed

  • Nothing yet.

[0.3.14] - 2025-12-26

Added

  • Version bump to 0.3.14

Changed

  • Nothing yet.

Fixed

  • Nothing yet.

[0.3.13] - 2025-12-24

Fixed

  • [DevX] k6 CRUD flow metric name sanitization (#79 follow-up): Fixed invalid k6 metric names in CRUD flow scripts when flow names contain dots or special characters
    • CRUD flow names are now sanitized for use as k6 metric names (e.g., plans.list → plans_list)
    • Original flow names preserved in comments and group names for readability
    • Made sanitize_js_identifier function public for reuse across k6 generators
    • Added script validation to CRUD flow generation for defense in depth

[0.3.12] - 2025-12-23

Changed

  • [DevX] Dependency updates: Version alignment and dependency updates across all workspace crates

[0.3.11] - 2025-12-19

Added

  • [DevX] Custom benchmark parameters: Added --params-file option to mockforge bench command for loading custom parameter values from a file

    Why it matters: Allows users to define reusable parameter configurations for benchmark runs, making it easier to test different scenarios without modifying command-line arguments each time.

[0.3.10] - 2025-12-18

Fixed

  • [DevX] k6 benchmark script generation fixes: Resolved multiple issues with generated k6 scripts
    • Fixed --insecure flag handling by moving insecureSkipTLSVerify to global k6 options
    • Fixed textSummary import and usage in generated scripts
    • Fixed query parameter encoding in benchmark requests

[0.3.9] - 2025-12-17

Added

  • [Reality] Comprehensive Mock Server Implementation: Full implementation across all protocol crates

    • mockforge-amqp: Complete AMQP 0-9-1 broker with exchanges, queues, bindings, messages, protocol handling, fixtures, and spec registry
    • mockforge-kafka: Full Kafka broker with consumer groups, partitions, topics, metrics, and protocol handling
    • mockforge-mqtt: Complete MQTT broker with QoS levels, topic subscriptions, and retained messages
    • mockforge-ftp: Virtual filesystem, spec registry, and fixture support
    • mockforge-smtp: Email server with fixtures and spec registry
    • mockforge-tcp: TCP server with fixtures and protocol support
    • mockforge-grpc: Dynamic proto parser, service generator, reflection, and metrics
    • mockforge-graphql: Full handler implementations
  • [DevX] Enhanced CLI Commands: New commands for all protocols and features

    • AMQP, Kafka, MQTT, FTP, SMTP protocol commands
    • Blueprint, cloud, deploy, dev-setup, governance commands
    • Logs, progress, recorder, scenario, snapshot commands
    • Time manipulation, VBR, voice, wizard, and workspace commands
    • AI-powered mock generation commands
  • [Reality] Virtual Backend Repository (VBR): Complete data management system

    • API generator, entity management, constraints, and validation
    • Database integration with migrations and schema management
    • Session handling, snapshots, and mutation rules
    • ID generation strategies and scheduling
  • [Reality] World State Engine: Coherent world simulation

    • State engine with model and query support
    • Entity relationships and lifecycle management
  • [AI] Enhanced AI Capabilities: AI-powered mock generation

    • RAG-based AI response generator
    • AI event generator for WebSocket scenarios
    • Behavioral cloning with scenario types
  • [Cloud] Collaboration Features: Team collaboration support

    • Backup, merge, and promotion workflows
    • Multi-environment configuration
    • Client SDK improvements
  • [DevX] Observability & Analytics: Enhanced monitoring

    • Pillar usage tracking and analytics queries
    • Metrics middleware and coverage tracking
    • Latency metrics and performance monitoring
  • [Contracts] Chaos Engineering: Resilience testing capabilities

    • Failure designer and incident replay
    • Chaos API with configurable fault injection
    • Route-level chaos with latency distributions
  • [DevX] Plugin System Enhancements: Extended plugin capabilities

    • Backend generator and datasource support
    • Runtime adapter improvements
    • SDK builders and testing utilities
  • [Cloud] Registry Server: Complete registry implementation

    • Authentication, authorization, and RBAC
    • Redis caching, email notifications
    • Organization and subscription models
    • API token management and audit logging
  • [DevX] UI Server: Dashboard and admin features

    • Admin handlers for workspace management
    • Chain visualization and coverage metrics
    • Failure analysis and promotion workflows
    • Graph visualization and health monitoring

[0.3.8] - 2025-01-27

Fixed

  • [DevX] Compilation errors resolved: Fixed all compilation errors across the workspace

    • Updated axum-server from 0.6 to 0.8 with tls-rustls-no-provider feature
    • Updated rustls from 0.21 to 0.23, rustls-pemfile from 1.0 to 2.0, tokio-rustls from 0.24 to 0.26
    • Adapted TLS code to rustls 0.23 API (CertificateDer, PrivateKeyDer, WebPkiClientVerifier)
    • Fixed multi_spec module: properly exported and resolved compilation errors
    • Fixed handle_serve function calls: added missing parameters and fixed type mismatches
    • Fixed borrow checker issues in multi_spec merging logic
    • Added missing documentation for enum variants and struct fields
    • Fixed various type mismatches and iteration patterns
  • [DevX] Cargo publish readiness: Fixed all dependency version requirements for crates.io publishing

    • Added version requirements to all path dependencies in mockforge-cli, mockforge-chaos, mockforge-http, mockforge-route-chaos, mockforge-vbr
    • Set publish = false for desktop-app and tests packages (not meant for crates.io)
    • All crates now pass cargo publish --dry-run validation

[0.3.6] - 2025-11-25

Fixed

  • [DevX] k6 script generation with operation IDs containing dots/hyphens (#79)

    • Fixed “Unexpected token .” error when OpenAPI operation IDs contain dots (e.g., plans.create) or hyphens (e.g., plans.update-pricing-schemes)
    • Changed is_alphanumeric() to is_ascii_alphanumeric() in JavaScript identifier sanitization to ensure ASCII-only identifiers
    • All operations are now properly included in generated k6 scripts with valid JavaScript identifiers
    • Added comprehensive tests including integration test with full billing subscriptions spec
  • [DevX] UI icon embedding for published crates

    • Fixed build failures when installing mockforge-cli from crates.io due to missing icon files
    • Updated build.rs to read icon files at build time and embed them as byte array literals
    • Replaced include_bytes! with CARGO_MANIFEST_DIR approach that failed in published crates
    • Icons are now properly embedded and work both in development and when installing from crates.io

[0.3.0] - 2025-11-17

Added

  • [DevX] Pillars & Tagged Changelog: Complete pillar system implementation with documentation and tooling

    • Defined five foundational pillars: [Reality], [Contracts], [DevX], [Cloud], [AI]
    • Added comprehensive PILLARS.md documentation with feature mappings
    • Implemented CI validation for pillar tags in changelog entries
    • Added pillar tagging instructions to release tooling
    • Updated README and getting-started guide with pillars section

    Why it matters: Clear product story spine that makes it obvious what each release invests in. Pillar tags help users understand product direction and find features relevant to their needs.

  • [Reality] Smart Personas & Reality Continuum v2: Complete persona graph and lifecycle system

    • Persona graphs with relationship linking across entities
    • Lifecycle states (NewSignup, Active, PowerUser, ChurnRisk, Churned, etc.)
    • Reality Continuum integration with field-level and entity-level mixing
    • Fidelity score calculation and API endpoint
    • Comprehensive PERSONAS.md documentation

    Why it matters: Upgrade from “random-but-consistent fake data” to “coherent world simulation.” Personas maintain relationships across endpoints, and fidelity scores quantify how real your mock environment is.

  • [Contracts] Drift Budget & GitOps for API Sync: Complete drift management system

    • Hierarchical drift budget configuration (global, workspace, service, endpoint)
    • Breaking change detection and classification
    • Incident management with webhook integration
    • GitOps PR generation for contract updates
    • Comprehensive DRIFT_BUDGETS.md documentation

    Why it matters: Make MockForge the “drift nerve center” for contracts. Define acceptable drift, get alerts when budgets are exceeded, and automatically generate PRs to update contracts and fixtures.

  • [Reality] Behavioral Cloning v1: Multi-step flow recording and replay

    • Flow recording with request/response capture and timing
    • Flow viewer with timeline visualization
    • Scenario replay engine with strict/flex modes
    • Scenario storage and export/import (YAML/JSON)
    • Comprehensive BEHAVIORAL_CLONING.md documentation

    Why it matters: Move from endpoint-level mocks to journey-level simulations. Record realistic flows from real systems and replay them as named scenarios for comprehensive testing.

  • [AI][DevX] LLM/Voice Interface for Workspace Creation: Natural language to complete workspace

    • Natural language workspace creation from descriptions
    • Automatic persona and relationship generation
    • Behavioral scenario generation (happy path, failure, slow path)
    • Reality continuum and drift budget configuration from NL
    • Voice and text input support
    • Comprehensive LLM Studio documentation

    Why it matters: The golden path: “Describe the system in natural language → MockForge builds a realistic mock backend with personas, behaviors, and reality level config.” No manual configuration required.

  • [DevX] Comprehensive Integration Test Coverage: Complete test suite for all 0.3.0 features

    • Smart Personas v2 integration tests (15 tests covering persona graphs, lifecycle states, fidelity scores)
    • Drift Budget integration tests (14 tests covering budget hierarchy, breaking change detection, incident management)
    • Drift GitOps integration tests (16 tests covering PR generation, OpenAPI/fixture updates, GitOps configuration)
    • Behavioral Cloning integration tests (15 tests covering flow recording, scenario replay, strict/flex modes)
    • Voice/LLM Workspace Creation integration tests (16 tests covering command parsing, workspace building, NL to workspace flow)
    • All tests passing with 100% success rate (76 total integration tests)

    Why it matters: Production-ready features require production-ready tests. Comprehensive integration test coverage ensures reliability, prevents regressions, and provides confidence for users adopting these features.

Changed

  • Changelog entries now require pillar tags for all major features
  • Release process includes automated pillar tag validation
  • Documentation structure updated to highlight pillars

Fixed

  • Nothing yet.

Security

  • Nothing yet.

[0.2.9] - 2025-11-14

Added

  • [Cloud] Registry server improvements with password reset functionality

    Why it matters: Enable seamless team collaboration with secure registry access—teams can share and discover mock scenarios without friction, and password reset keeps workflows moving when credentials are lost.

  • [Cloud] Enhanced metrics and marketplace features

  • [DevX] Comprehensive E2E test suite

  • [DevX] Custom routes implementation

  • [Reality] Template expansion improvements

  • [Reality] Latency injection enhancements

  • [Reality] Smart Personas with array generation and relationship inference

    Why it matters: Generate realistic, interconnected mock data automatically—arrays that make sense, relationships that stay consistent across endpoints, and personas that feel like real users without manual configuration.

  • [DevX] Complete Java and .NET SDK implementations with builder patterns

    Why it matters: Bring MockForge to enterprise teams using Java and .NET—no more language barriers, no more custom integration work. Your entire stack can use the same mock infrastructure.

  • [Cloud] Cloud monetization infrastructure and features

    Why it matters: Enable sustainable platform growth with flexible pricing models—teams can scale from free tier to enterprise without friction, and the platform can grow while serving developers.

  • [Cloud] Organization management endpoints

    Why it matters: Scale from solo developer to enterprise team—manage users, permissions, and resources at the org level, not just individual accounts. Real teams need real organization tools.

  • [Cloud] Security controls implementation (Phase 3)

    Why it matters: Protect production deployments with enterprise-grade security—fine-grained access controls, audit trails, and compliance features that let you trust MockForge with sensitive data and critical workflows.

Changed

  • [DevX] Upgraded wasmtime to 36.0.3 to fix RUSTSEC-2025-0118
  • [DevX] Fixed Axum 0.8 route syntax compatibility across multiple modules
  • [DevX] Updated all test files for new function signatures

Fixed

  • [DevX] Fixed compilation errors across workspace
  • [DevX] Fixed Axum 0.8 route syntax in state_machine_api.rs
  • [DevX] Fixed file server route syntax for Axum 0.8 compatibility
  • [DevX] Resolved all compilation errors for comprehensive test coverage

Security

  • [DevX] Upgraded wasmtime to 36.0.3 to address RUSTSEC-2025-0118
  • [Cloud] Completed Phase 3 security controls implementation

[0.2.8] - 2025-11-10

Added

  • [Reality] Generative Schema Mode: Complete implementation of generative schema mode for dynamic mock data generation

    Why it matters: Spin up a believable API even when the backend doesn’t exist yet—no sample DB or seed data required.

  • [Reality] Smart Personas: Feature for consistent cross-endpoint data generation using persona-based templates

  • [Reality] Reality Continuum: Feature for blending mock and real data sources with configurable reality levels

    Why it matters: Turn the dial between deterministic mock and noisy production-like chaos without changing your client code.

  • [Reality] Reality Slider: Hot-reload support for reality level adjustments

    Why it matters: Adjust reality levels on the fly during development and testing without restarting the server.

  • [Reality] Chaos Lab: Interactive network condition simulation tool

    Why it matters: Test how your application handles real-world network conditions like latency spikes, packet loss, and connection failures.

  • [Contracts] AI Contract Diff: Feature for comparing and diffing API contracts

    Why it matters: Automatically detect and visualize API contract changes to catch breaking changes before they reach production.

  • [DevX] Voice + LLM Interface: Voice interface implementation with Speech-to-Text (STT) backend support

  • [Reality] Deceptive Deploy: Complete deceptive deploy feature for advanced testing scenarios

  • [DevX] GraphQL + REST Playground: Interactive playground with workspace filtering capabilities

  • [DevX] ForgeConnect SDK: Complete SDK implementation with full feature set

  • [Cloud] Enhanced Scenario Marketplace: Improved scenario marketplace with additional features

  • [DevX] WireMock-Inspired Features: Browser proxy mode, git sync, data sources, template library, managed hosting documentation, and user management

  • [DevX] Ecosystem Documentation: Comprehensive ecosystem and use cases documentation

  • [DevX] Configuration Extensibility: Complete configuration and extensibility implementation

  • [Reality] Advanced Behavior Simulation: Enhanced behavior and simulation features

Changed

  • [DevX] SQLx Integration: Configured SQLx and integrated mockforge-collab with mockforge-core
  • [Reality] Latency Recording: Completed latency recording integration with WorkspaceConfig reality_level field support

Fixed

  • [DevX] Fixed test compilation errors in reality integration and hot-reload tests
  • [DevX] Fixed test compilation errors in openapi_generator_tests
  • [Contracts][DevX] Fixed all compilation errors for AI Contract Diff feature
  • [DevX] Applied rustfmt formatting to Chaos Lab code

Security

  • Nothing yet.

[0.2.7] - 2025-11-05

Added

  • [Contracts] Automatic API Sync & Change Detection: Implemented periodic polling and automatic sync for detecting upstream API changes

    Why it matters: Keep your mocks in sync with real APIs automatically—catch breaking changes before they break your tests.

    • Periodic sync service with configurable intervals (default: 1 hour)
    • Automatic change detection using deep response comparison (status, headers, body)
    • Optional automatic fixture updates when changes detected
    • Manual sync trigger via API (POST /api/recorder/sync/now)
    • Sync status tracking and change history
    • Configurable sync settings: upstream URL, interval, headers, timeout, max requests
    • Support for GET-only or all-methods sync
    • Detailed change reports with before/after comparisons
    • Database update method for refreshing recorded responses
    • API endpoints: /api/recorder/sync/status, /api/recorder/sync/config, /api/recorder/sync/changes
  • [Reality] TCP Protocol Support: Added raw TCP server mocking support via new mockforge-tcp crate

    Why it matters: Mock any protocol that runs over TCP—not just HTTP. Perfect for testing database clients, custom protocols, and legacy systems.

    • Raw TCP connection handling with fixture-based matching
    • Echo mode for testing TCP clients
    • TLS/SSL support for encrypted connections
    • Delimiter-based message framing (optional)
    • Configurable buffer sizes and connection limits
    • CLI flag --tcp-port for custom TCP server port
    • Configuration via config.tcp in YAML/JSON config files
  • [Reality] Response Selection Modes: Added support for sequential (round-robin) and random response selection when multiple examples are available

    • Sequential mode: Cycles through available examples in order (round-robin)
    • Random mode: Randomly selects from available examples
    • Weighted random mode: Random selection with custom weights per example
    • Configuration via x-mockforge-response-selection OpenAPI extension
    • Environment variable support: MOCKFORGE_RESPONSE_SELECTION_MODE (global) and MOCKFORGE_RESPONSE_SELECTION_<OPERATION_ID> (per-operation)
    • State tracking for sequential mode ensures round-robin behavior across requests
  • [Reality] Webhook HTTP Execution: Implemented actual HTTP request execution in chaos orchestration hooks

    • HookAction::HttpRequest now executes real outbound HTTP requests (previously only logged)
    • Supports GET, POST, PUT, DELETE, PATCH methods
    • Configurable request body and headers
    • Error handling and logging for webhook failures
    • Fire-and-forget execution (failures don’t block orchestration)
  • [DevX] CRUD & Webhook Documentation: Added comprehensive documentation guides

    • docs/CRUD_SIMULATION.md: Complete guide for simulating CRUD operations with stateful data store
    • docs/WEBHOOKS_CALLBACKS.md: Full documentation of webhook capabilities via hooks, chains, and scripts
    • Examples demonstrating realistic workflows and integrations

Changed

  • Nothing yet.

Deprecated

  • Nothing yet.

Removed

  • Nothing yet.

Fixed

  • Nothing yet.

Security

  • Nothing yet.

[0.2.6] - 2025-11-04

Added

  • [DevX] TLS/HTTPS and mTLS Support: Added TLS/HTTPS and mutual TLS (mTLS) support for HTTP server

    • Configurable TLS certificate and key paths
    • Client certificate authentication support
    • Secure connection handling for production deployments
  • [DevX] Built-in Tunneling Service: Added built-in tunneling service for exposing local servers via public URLs

    • Automatic tunnel creation for local development
    • Public URL generation for testing and demos
    • Integration with popular tunneling services
  • [DevX] SDK Implementation: Completed Phase 1 & 2 of SDK implementation

    • Comprehensive documentation and examples
    • Production-ready client generators

Changed

  • [DevX] Version Bumps: Updated all workspace crates from 0.2.5 to 0.2.6

    • Updated all dependency versions across the workspace
    • Fixed version mismatches in mockforge-ui and mockforge-plugin-loader
  • [DevX] Publishing Improvements: Enhanced crate publishing process

    • Added mockforge-tcp and mockforge-test to publish script
    • Enabled publishing for mockforge-test crate
    • Fixed mockforge-tcp to remove README requirement

Fixed

  • [DevX] Documentation: Fixed missing module-level documentation in test files

    • Added comprehensive module documentation to all test modules
    • Improved code documentation consistency
  • [DevX] Axum Compatibility: Fixed Axum 0.8 compatibility issues in proxy server module

    • Updated proxy server to work with latest Axum version
    • Resolved breaking changes from Axum upgrade
  • [Reality] MQTT Error Types: Fixed MQTT publish handlers error types to be Send + Sync

    • Updated error types for proper async/await compatibility
    • Ensured thread-safety in MQTT handlers

[0.2.5] - 2025-01-27

Added

  • [DevX] OAuth2 Flow Support: Complete OAuth2 implementation with all standard flows

    • Authorization Code flow with PKCE (RFC 7636 compliant, SHA256 hash)
    • Client Credentials flow for server-side applications
    • Password flow for trusted clients
    • Implicit flow support
    • Automatic token refresh and expiration management
    • State parameter for CSRF protection
    • PKCE code verifier/challenge generation helpers
    • Token storage with expiration tracking (localStorage)
  • [DevX] Enterprise Error Handling: Structured error handling for generated clients

    • ApiError class with status codes, statusText, and error body
    • RequiredError class for missing required fields
    • Helper methods: isClientError(), isServerError(), getErrorDetails(), getVerboseMessage()
    • Optional verbose error messages with detailed validation information
  • [Contracts] Request/Response Validation: Built-in validation support

    • Required field validation before sending requests
    • Basic response structure validation (type checking, object validation)
    • Configurable via validateRequests flag
    • Detailed validation error messages
  • [DevX] Request/Response Interceptors: Custom request/response/error transformation

    • Request interceptor: Modify requests before sending
    • Response interceptor: Transform responses after receiving
    • Error interceptor: Global error handling
    • Support for async interceptors
  • [DevX] Enhanced Authentication: Multiple authentication methods

    • Bearer token (static or dynamic function)
    • API key authentication (static or dynamic)
    • Basic authentication (username/password)
    • OAuth2 (all flows, takes priority over other methods)
  • [DevX] PKCE Helper Functions: Exported utilities for PKCE implementation

    • generatePKCECodeVerifier(): Generate cryptographically random code verifier
    • generatePKCECodeChallenge(): Generate SHA256 code challenge from verifier
  • [DevX] Security Best Practices: Comprehensive security warnings and guidance

    • Client secret warnings for browser-based applications
    • XSS vulnerability warnings for localStorage token storage
    • CSRF protection via state parameter validation
    • Token expiration checking
    • Security documentation in generated README
  • [DevX] Request Timeout Handling: Configurable request timeouts

    • Default 30-second timeout (configurable)
    • AbortController-based timeout implementation
    • Proper timeout error handling
  • [DevX] React Query Integration Documentation: Comprehensive examples for @tanstack/react-query integration

Changed

  • [DevX] React Client Generator: Major enhancements to generated React client code

    • Replaced placeholder PKCE implementation with full SHA256-based solution
    • Implemented proper response validation (previously placeholder)
    • Enhanced README with comprehensive feature documentation
    • Improved error messages and validation details
    • Better security documentation and best practices
  • [DevX] Operation ID Sanitization: Improved identifier generation

    • Enhanced sanitize_identifier function to handle complex operation IDs
    • Better handling of parentheses, slashes, hyphens in operation IDs
    • Proper camelCase conversion with word boundary detection

Fixed

  • [DevX] TypeScript Empty Object Types: Fixed formatting issue where empty object schemas generated invalid TypeScript

    • Empty objects now correctly generate as [key: string]: any; instead of malformed Record<string, any>}
  • [DevX] DELETE Operations with Query Params: Fixed missing query parameter support in DELETE operations

  • [DevX] Duplicate Operation IDs: Fixed duplicate operation ID handling by appending numeric suffixes

  • [DevX] PKCE Code Challenge: Fixed PKCE implementation to use proper SHA256 hash instead of plain encoding

  • [Contracts][DevX] Response Validation: Replaced placeholder with actual implementation (type checking, structure validation)

Security

  • [DevX] Added comprehensive security warnings for OAuth2 client secrets in browser code
  • [DevX] Added XSS vulnerability warnings for localStorage token storage
  • [DevX] Implemented CSRF protection via state parameter validation
  • [DevX] Added token expiration checking to prevent use of expired tokens
  • [DevX] Documented security best practices in generated client README

[0.2.4] - 2025-01-27

Fixed

  • [DevX] Fix request body parameter generation in React/Vue/Svelte client generators - request bodies now correctly generate data parameter and body: JSON.stringify(data) in API client methods
  • [DevX] Fix required vs optional field handling in generated TypeScript interfaces - required fields no longer incorrectly marked with optional marker (?)
  • [DevX] Fix OpenAPI serde deserialization by adding #[serde(rename)] attributes for operationId and requestBody fields
  • [DevX] Apply required fields processing consistently across all client generators (React, Vue, Svelte)

Added

  • [DevX] Comprehensive test coverage for request body parameter scenarios (POST, PUT, PATCH, DELETE)
  • [DevX] Test cases for $ref schemas in request bodies
  • [DevX] Test cases for YAML spec support verification

[0.2.3] - 2025-01-27

Fixed

  • [DevX] Fix OpenAPI example extraction to prioritize explicit examples from schema and properties
  • [DevX] Fix request body parameter generation in React client generator for POST, PUT, PATCH, DELETE methods
  • [DevX] Fix Handlebars template logic for request body type generation in client code
  • [DevX] Fix useCallback dependency array formatting in React hooks template
  • [DevX] Add comprehensive test coverage for request body parameter scenarios

[0.2.0] - 2025-10-29

Added

  • [DevX] Output control features for MockForge generator with comprehensive configuration options
  • [DevX] Unified spec parser with enhanced validation and error reporting
  • [DevX] Multi-framework client generation with Angular and Svelte support
  • [Reality] Enhanced mock data generation with OpenAPI support
  • [DevX] Configuration file support for mock generation
  • [DevX] Browser mobile proxy mode implementation
  • [DevX] Comprehensive documentation and example workflows

Changed

  • [DevX] Enhanced CLI with progress indicators, error handling, and code quality improvements
  • [DevX] Comprehensive plugin architecture documentation

Fixed

  • [DevX] Remove tests that access private fields in mock data tests
  • [DevX] Fix compilation issues in mockforge-collab and mockforge-ui
  • [DevX] Update mockforge-plugin-core version to 0.1.6 in plugin-sdk
  • [DevX] Enable SQLx offline mode for mockforge-collab publishing
  • [DevX] Add description field to mockforge-analytics
  • [DevX] Add version requirements to all mockforge path dependencies
  • [DevX] Fix publish order dependencies (mockforge-chaos before mockforge-reporting)
  • [DevX] Update Cargo.lock and format client generator tests

[0.1.3] - 2025-10-22

Changes

  • [DevX] docs: prepare release 0.1.3
  • [DevX] docs: update CHANGELOG for 0.1.3 release
  • [DevX] docs: add roadmap completion summary
  • [DevX] feat: add Kubernetes-style health endpoint aliases and dashboard shortcut
  • [DevX] feat: add unified config & profiles with multi-format support
  • [Reality] feat: add capture scrubbing and deterministic replay
  • [DevX] feat: add native GraphQL operation handlers with advanced features
  • [Reality] feat: add programmable WebSocket handlers
  • [Reality] feat: add HTTP scenario switching for OpenAPI response examples
  • [DevX] feat: add mockforge-test crate and integration testing examples
  • [DevX] build: enable publishing for mockforge-ui and mockforge-cli
  • [DevX] build: extend publish script for internal crates
  • [DevX] build: parameterize publish script with workspace version

[0.1.2] - 2025-10-17

Changes

  • [DevX] build: make version update tolerant
  • [DevX] build: manage version references via wrapper
  • [DevX] build: mark example crates as non-publishable
  • [DevX] build: drop publish-order for cargo-release 0.25
  • [DevX] build: centralize release metadata in release.toml
  • [DevX] build: remove per-crate release metadata
  • [DevX] build: fix release metadata field name
  • [DevX] build: move workspace release metadata into Cargo.toml
  • [DevX] build: require execute flag for release wrapper
  • [DevX] build: automate changelog generation during release
  • [DevX] build: add release wrapper with changelog guard
  • [DevX] build: align release tooling with cargo-release 0.25

[0.1.1] - 2025-10-17

Added

  • [Contracts] OpenAPI request validation (path/query/header/cookie/body) with deep $ref resolution and composite schemas (oneOf/anyOf/allOf).
  • [Contracts] Validation modes: disabled, warn, enforce, with aggregate error reporting and detailed error objects.
  • [DevX] Runtime Admin UI panel to view/toggle validation mode and per-route overrides; Admin API endpoint /__mockforge/validation.
  • [DevX] CLI flags and config options to control validation (including skip_admin_validation and per-route validation_overrides).
  • [DevX] New e2e tests for 2xx/422 request validation and response example expansion across HTTP routes.
  • [DevX] Templating reference docs and examples; WS templating tests and demo update.
  • [Reality] Initial release of MockForge - Multi-protocol mocking framework
  • [Reality] HTTP API mocking with OpenAPI support
  • [Reality] gRPC service mocking with Protocol Buffers
  • [Reality] WebSocket connection mocking with replay functionality
  • [DevX] CLI tool for easy local development
  • [DevX] Admin UI for managing mock servers
  • [DevX] Comprehensive documentation with mdBook
  • [DevX] GitHub Actions CI/CD pipeline
  • [DevX] Security audit integration
  • [DevX] Pre-commit hooks for code quality

Changed

  • [Contracts] HTTP handlers now perform request validation before routing; invalid requests return 400 with structured details (when enforce).
  • [Contracts] Bump jsonschema to 0.33 and adapt validator API; enable draft selection and format checks internally.
  • [Contracts] Improve route registry and OpenAPI parameter parsing, including styles/explode and array coercion for query/header/cookie parameters.

Deprecated

  • N/A

Removed

  • N/A

Fixed

  • [DevX] Resolve admin mount prefix from config and exclude admin routes from validation when configured.
  • [Contracts] Various small correctness fixes in OpenAPI schema mapping and parameter handling; clearer error messages.

Security

  • N/A

Release Process

This project uses cargo-release for automated releases.

Creating a Release

  1. Patch Release (bug fixes):

    make release-patch
    
  2. Minor Release (new features):

    make release-minor
    
  3. Major Release (breaking changes):

    make release-major
    

Manual Release Process

If you need to do a manual release:

  1. Update version in Cargo.toml files
  2. Update CHANGELOG.md with release notes
  3. Commit changes: git commit -m "chore: release vX.Y.Z"
  4. Tag: git tag vX.Y.Z
  5. Push: git push && git push --tags
  6. Publish to crates.io: cargo publish

Pre-release Checklist

  • All tests pass (make test)
  • Code formatted (make fmt)
  • Lints pass (make clippy)
  • Security audit passes (make audit)
  • Documentation updated
  • Changelog updated
  • Version bumped in all Cargo.toml files
  • Breaking changes documented (if any)
  • CI passes on all branches