Stateful Mocking
Stateful mocking allows mockd to simulate real CRUD APIs where resources persist across requests. Create, update, and delete operations modify state that subsequent requests can observe.
Overview
Section titled “Overview”Traditional mocks return static responses. Stateful mocking maintains an in-memory store that:
- POST creates new resources
- GET retrieves current resources
- PUT replaces existing resources
- DELETE removes resources
Changes persist for the lifetime of the server session.
Quick Start
Section titled “Quick Start”Enable stateful mocking in your configuration:
{ "statefulResources": [ { "name": "users", "basePath": "/api/users", "idField": "id" } ]}Start the server and interact:
# Create a usercurl -X POST http://localhost:4280/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice", "email": "alice@example.com"}'# Response: {"id": 1, "name": "Alice", "email": "alice@example.com"}
# List users - Alice is now in the listcurl http://localhost:4280/api/users# Response: [{"id": 1, "name": "Alice", "email": "alice@example.com"}]
# Get single usercurl http://localhost:4280/api/users/1# Response: {"id": 1, "name": "Alice", "email": "alice@example.com"}
# Update usercurl -X PUT http://localhost:4280/api/users/1 \ -H "Content-Type: application/json" \ -d '{"name": "Alice Smith", "email": "alice@example.com"}'# Response: {"id": 1, "name": "Alice Smith", "email": "alice@example.com"}
# Delete usercurl -X DELETE http://localhost:4280/api/users/1# Response: 204 No Content
# User is gonecurl http://localhost:4280/api/users/1# Response: 404 Not FoundConfiguration
Section titled “Configuration”Basic Resource
Section titled “Basic Resource”{ "statefulResources": [ { "name": "users", "basePath": "/api/users" } ]}| Field | Description | Default |
|---|---|---|
name | Unique resource name | Required |
basePath | URL path prefix for the resource | Required |
idField | Field name for resource ID | "id" |
parentField | Parent FK field for nested resources | - |
seedData | Initial data array | [] |
Multiple Resources
Section titled “Multiple Resources”{ "statefulResources": [ { "name": "users", "basePath": "/api/users" }, { "name": "posts", "basePath": "/api/posts" }, { "name": "comments", "basePath": "/api/posts/:postId/comments", "parentField": "postId" } ]}Initial Data (Seeding)
Section titled “Initial Data (Seeding)”Pre-populate resources:
{ "statefulResources": [ { "name": "users", "basePath": "/api/users", "seedData": [ {"id": "1", "name": "Alice", "email": "alice@example.com"}, {"id": "2", "name": "Bob", "email": "bob@example.com"} ] } ]}CRUD Operations
Section titled “CRUD Operations”Create (POST)
Section titled “Create (POST)”POST /api/usersContent-Type: application/json
{"name": "Charlie", "email": "charlie@example.com"}Response:
{ "id": 3, "name": "Charlie", "email": "charlie@example.com"}Status: 201 Created
Read Collection (GET)
Section titled “Read Collection (GET)”GET /api/usersResponse:
[ {"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}, {"id": 3, "name": "Charlie"}]Read Single (GET)
Section titled “Read Single (GET)”GET /api/users/2Response:
{"id": 2, "name": "Bob", "email": "bob@example.com"}Not found:
GET /api/users/999Response: 404 Not Found
Update (PUT)
Section titled “Update (PUT)”Replace entire resource:
PUT /api/users/2Content-Type: application/json
{"name": "Robert", "email": "robert@example.com"}Response:
{"id": 2, "name": "Robert", "email": "robert@example.com"}Delete (DELETE)
Section titled “Delete (DELETE)”DELETE /api/users/2Response: 204 No Content
Nested Resources
Section titled “Nested Resources”Handle parent-child relationships:
{ "statefulResources": [ { "name": "posts", "basePath": "/api/posts" }, { "name": "comments", "basePath": "/api/posts/:postId/comments", "parentField": "postId" } ]}Comments are scoped to their parent post:
# Get comments for post 1GET /api/posts/1/comments
# Create comment on post 1POST /api/posts/1/comments{"text": "Great post!"}Filtering and Pagination
Section titled “Filtering and Pagination”Query Filtering
Section titled “Query Filtering”Filter by any field using query parameters:
GET /api/users?name=AliceGET /api/users?status=activeFiltering is always enabled.
Pagination
Section titled “Pagination”Use offset-based pagination:
GET /api/users?limit=10&offset=20GET /api/users?sort=name&order=ascQuery parameters:
| Parameter | Description | Default |
|---|---|---|
limit | Maximum items to return | 100 |
offset | Items to skip | 0 |
sort | Field to sort by | createdAt |
order | Sort direction: “asc” or “desc” | desc |
Response includes pagination metadata:
{ "data": [...], "meta": { "total": 45, "limit": 10, "offset": 20, "count": 10 }}Validation
Section titled “Validation”Validate incoming requests before creating or updating resources. Validation ensures data integrity by checking field types, formats, constraints, and required fields.
Quick Example
Section titled “Quick Example”statefulResources: - name: users basePath: /api/users validation: mode: strict fields: email: type: string required: true format: email username: type: string required: true minLength: 3 maxLength: 30 pattern: "^[a-z][a-z0-9_]*$" age: type: integer min: 0 max: 150 role: type: string enum: [admin, user, guest]Validation Modes
Section titled “Validation Modes”| Mode | Behavior |
|---|---|
strict | Reject request on any validation failure (default) |
warn | Log warnings but allow request through |
permissive | Only fail on critical errors (missing required fields) |
Nested Fields
Section titled “Nested Fields”Validate nested object fields using dot notation:
fields: "address.city": type: string required: true "items.sku": type: string pattern: "^SKU-[A-Z0-9]+$"For nested objects, array validation, formats, patterns, and more, see the Validation Guide.
State Lifetime
Section titled “State Lifetime”State exists only in memory and resets when the server stops. Use seed data to pre-populate resources on startup.
Admin API
Section titled “Admin API”Manage state via the admin API:
# Get state overviewGET /state
# Reset all state to seed dataPOST /state/reset
# List all resourcesGET /state/resources
# Get specific resource infoGET /state/resources/users
# Clear specific resource (remove all items)DELETE /state/resources/usersCombined with Static Mocks
Section titled “Combined with Static Mocks”Stateful resources work alongside traditional mocks:
{ "mocks": [ { "matcher": {"method": "GET", "path": "/api/health"}, "response": {"statusCode": 200, "body": {"status": "ok"}} } ], "statefulResources": [ { "name": "users", "basePath": "/api/users" } ]}Static mocks take priority when matched.
Complete Example
Section titled “Complete Example”{ "server": { "port": 4280 }, "statefulResources": [ { "name": "users", "basePath": "/api/users", "idField": "id", "seedData": [ {"id": "1", "name": "Admin", "role": "admin"} ] }, { "name": "posts", "basePath": "/api/posts" } ]}Next Steps
Section titled “Next Steps”- Proxy Recording - Record real API traffic
- Admin API Reference - State management endpoints
- Configuration Reference - Full schema