Virtual Backend Reality (VBR) Engine
Experimental. This feature ships in MockForge but is early: the engine and the
mockforge vbrcommands work, but it is not yet enabled frommockforge serve(there is no--vbr-enabledflag orvbr: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:
SQLite (Recommended)
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
- Use SQLite for Production: SQLite provides the best balance of performance and features
- Seed Initial Data: Use seed files for consistent starting states
- Create Snapshots: Save important states for quick restoration
- Configure TTL: Use time-based expiry for session-like data
- Version Control Seed Files: Keep seed data in version control
- 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
Related Documentation
- Temporal Simulation - Time-based data mutations
- Scenario State Machines - State machine integration
- Configuration Guide - Complete configuration reference