In modern software development, teams are rarely in perfect sync. While backend engineers are busy setting up databases and wiring complex business logic, frontend and QA teams are often stuck waiting, blocked by APIs that "aren't ready yet."
The first, Level 1 approach most developers reach for is static API mocking. This is great, and works fine for simple requests like a GET /users/
or GET /users/{id}
, but it falls apart the moment you try to simulate anything complex. Real-world applications rely on state; they track user sessions, build shopping carts, and guide users through multi-step forms where the second API call depends on the result of the first.
This is exactly where Beeceptor’s stateful mocking come in to transform your development workflow. You can implement real data persistence without requiring to set up a single database, instantly unblocking your frontend and QA teams.
The Problem: Why do Static Mocks Fail Real-World Workflows?
To truly appreciate stateful mocking, we first need to understand the frustrating limits of static mocks.
Imagine a common, three-step user journey:
-
POST /start-form
: Saves the user’s name and returns a temporaryformId
. -
POST /add-details
: Submits the user’s age, referencing that specificformId
. -
GET /summary
: Loads the completed form data (Name and Age).
If you use static mocks, the GET /summary
endpoint will always return the same hardcoded name and age again, and again. It simply can't "remember" the dynamic formId
from step 1 or the actual data submitted in step 2. The result? Your developers are blocked from properly testing the full user experience, forcing them to just wait for the real backend to go live.
The Beeceptor Solution: Persistence Without Setting up a Database
Beeceptor solves this dependency hell by giving you a persistent state store right inside your mock endpoint. You manage this store entirely through Beeceptor’s powerful, no-code templating, letting you create realistic, dynamic state flows without writing any backend code, or managing infrastructure.
Beeceptor provides three essential, easy-to-use building blocks for managing state:
1. The Data Store (data-store
)
This is a simple key-value store, perfect for persisting any single value that defines a session or workflow.
Use Cases: Saving a generated session token after a mock login, storing the user’s name from a form step, or persisting a full configuration object.
Example (Saving a Name): To extract the
userName
from the request body and save it for later:
{{data-store 'set' 'currentUserName' (body 'userName')}}
{ "message": "Name saved." }
2. The List (list
)
The List helper manages an ordered collection (like an array) of values. This is ideal for simulating dynamic items being added over time.
Use Case: Incrementally adding to-do items to a list, or logging a sequence of user actions.
Example (Adding a To-Do Item): To append a new task to a list named
myTasks
:
{{list 'push' 'myTasks' (body 'taskDescription')}}
{ "tasks_count": "{{list 'len' 'myTasks'}}", "message": "Task added." }
3. The Step Counter (step-counter
)
This is a simple numeric counter that you can increment, decrement, or reset. It's invaluable for generating unique IDs or tracking sequential steps.
Use Case: Generating a new, sequential notification ID for every request, or tracking how many times a user has performed an action.
Example (Generating ID): To increment a counter and use the new value as a unique ID:
{{step-counter 'inc' 'notificationCounter' 1}}
{ "notification_id": "{{step-counter 'get' 'notificationCounter'}}", "status": "sent" }
Bringing it Together: A Stateful Shopping Cart API
Let's use this knowledge to create a simple stateful Mock API where a user adds items to a history list and then retrieves the final list and count using a single endpoint: /api/item
. We’ll use POST /api/item
to save data and GET /api/item
to retrieve the full state.
1. The POST /api/item
Endpoint (Saving State)
This endpoint accepts a simple JSON request body like {"itemName": "Tide Pods"}
.
It then uses the List (product_history
) to track the item and the Step Counter (orderCounter
) for the running order count.
POST /api/item
Mock Response Template (Status code: 201):
{{list 'push' 'product_history' (body 'itemName')~}}
{{step-counter 'inc' 'orderCounter' 1~}}
{
"message": "Item added successfully.",
"item_added": "{{ body 'itemName' }}",
"order_count": {{step-counter 'get' 'orderCounter'}}
}
This template instantly saves the new item and increments the counter, returning a dynamic confirmation. (The tilde ~
operator is a handlebar implement, it simply cleans up the JSON by removing newlines from hidden helper statements.)
2. The GET /api/item
Endpoint (Retrieving State)
This subsequent call retrieves the full state from memory, providing the complete list of all items added so far and the final count.
GET /api/item
Mock Response Template (Status code: 200):
{
"order_count": {{step-counter 'get' 'orderCounter'}},
"product_history": [
{{#each (list 'get' 'product_history')}}
"{{this}}"{{#unless @last}},{{/unless}}
{{/each}}
]
}
This simple sequence transforms your mock into a fully interactive, stateful API simulation. Your frontend team can now build and test the entire user journey—repeatedly calling the POST
endpoint, seeing the item count update in real time, and viewing the correct, dynamic list—all without needing a single line of production backend code.
Stateful mocking with Beeceptor means your teams can work independently, simplify testing against complex, sequential API logic, etc., and thus, ship features faster.
Top comments (0)