Skip to documentation

Guide · Stateful behavior

Available

Model data that survives the request

Use one atomic runtime for visual state actions and template helpers. State is isolated by workspace and API scope, while dynamic keys let you model individual customers, sessions, carts, jobs, or entities.

In this guide

  • Choose the correct resource type
  • Scope state to one API or share it across a workspace
  • Use atomic before and inline mutations
  • Reset, snapshot, restore, and audit live data safely

Prerequisites

  • A DotMock workspace you can access
  • The API ID in $API_ID and its published runtime URL in $MOCK_URL when the example calls the mock
On this page

Choose the resource by behavior

A resource definition describes the data structure, initial value, scope, and optional TTL. Live entries are separate from the definition, so publishing configuration does not erase them.

  • Map — address arbitrary JSON by key, such as users-by-id
  • Counter — atomic request counts, quotas, inventory, and sequence numbers
  • List — ordered values with push, unshift, pop, and shift
  • Queue — FIFO jobs, scripted outcomes, and event sequences
  • Stack — LIFO undo history and nested workflows
  • Set — unique membership and deduplication
  • Collection — schema-aware CRUD records
  • State machine — validated transitions such as pending → paid → refunded

Use the narrowest useful scope

API scope is the default. Only the current API can resolve that resource. Workspace scope makes the definition and live namespace visible to every API in the same team workspace, which is useful when a REST API creates data that GraphQL, gRPC, LLM, or webhook behavior must read.

Understand the atomic execution order

Each request runs Match → Before actions → Template rendering → Response → After actions. Before actions and inline mutations share one atomic transaction. A validation or render failure commits nothing.

After actions are durable and retried, but they cannot change the response that was already selected. Use them for response hooks and follow-up effects, not response selection.

text
Match → Before actions → Template rendering → Response → After actions

Use proven state patterns

Dynamic keys come from the current protocol scope. REST uses path parameters, query values, headers, and body paths; GraphQL uses variables and arguments; gRPC uses typed message fields and metadata; LLM fixtures use normalized request data; webhook templates use trigger data.

Create one REST record
{{state.create "users-by-id"}}

Increment per customer
{{state.increment "request-count" "$header.x-customer-id" 1}}

Consume a scripted outcome
{{queue.pop "checkout-outcomes" "$header.x-test-run"}}

Add unique membership
{{set.add "seen-products" "$body.customerId" "sku_123"}}

Manage live values without surprises

Reads never extend a TTL. Successful writes refresh it. Editing an initial value affects only new or reset entries, and incompatible type changes are blocked while live values exist.

Use search and paginated entry inspection for routine edits. Snapshot before a destructive experiment, restore only with confirmation, and use the audit log to identify the endpoint, CLI, agent, or UI action responsible for the last write.

  • Publishing preserves live values
  • Reset explicitly returns entries to their initial state
  • Snapshots and definitions are durable control-plane records
  • Live values stay in API-isolated Redis namespaces
  • Redis outages leave stateless mocks available while state-dependent requests fail closed with 503
DotMock state workspace with searchable live values and separate Definition, Snapshots, and Audit log tabs
Live values are inspectable and editable without mixing them with the resource definition or its restore history.

Preview the exact diff

A safe tester run uses an isolated overlay. It never writes Redis and returns the exact proposed state diff alongside the winning response. Use a fixed seed and run ID for concurrent or sequence-sensitive tests.

bash
dotmock --json test --api "$API_ID" --method POST --path /users --body @user.json --seed 42