Back to Blog
Stateful Mock APIs That Remember Things
Tutorials 6 min read

Stateful Mock APIs That Remember Things

Most mock servers return canned responses. mockd keeps state — create a user, and it actually exists. Delete it, and it's gone. One command to get a full CRUD API.

ZS
Zach Snell
March 1, 2026

Last month I was helping a friend prototype a React app. He had a login screen, a dashboard, and a settings page — all wired up to fetch() calls against an API that didn’t exist yet. His backend developer was two sprints behind.

His solution? A db.json file and a bunch of if statements in a local Express server. Create a user? Manually append to the array, write the file, hope nothing races. Delete a user? Splice by index and pray.

It worked. Barely. And every time he restarted the server, he had to re-seed the data by hand.

This is the problem mockd solves with stateful resources. One command gives you a full CRUD API that actually remembers what you did.

One command, five endpoints

mockd add --path /api/users --stateful users
Created stateful resource: users
  Base path: /api/users
  Endpoints:
    GET    /api/users        — List all users
    POST   /api/users        — Create a user
    GET    /api/users/{id}   — Get a user by ID
    PUT    /api/users/{id}   — Update a user
    DELETE /api/users/{id}   — Delete a user

That’s it. You now have a working REST API with in-memory storage. No schema to define, no database to configure, no boilerplate server code.

The full lifecycle

Let’s walk through it. Create a user:

curl -X POST http://localhost:4280/api/users 
  -H "Content-Type: application/json" 
  -d '{"name":"Alice","email":"alice@example.com"}'

mockd auto-generates an id (UUID), createdAt, and updatedAt for you. The response comes back with all of it.

Now list users:

curl http://localhost:4280/api/users
{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "name": "Alice",
      "email": "alice@example.com",
      "createdAt": "2026-02-28T10:30:00Z",
      "updatedAt": "2026-02-28T10:30:00Z"
    }
  ],
  "meta": {
    "total": 1,
    "limit": 100,
    "offset": 0,
    "count": 1
  }
}

Alice is there. She didn’t come from a JSON file or a hardcoded fixture — the server created her and is holding her in memory.

Get her by ID:

curl http://localhost:4280/api/users/{id}

Update her:

curl -X PUT http://localhost:4280/api/users/{id} 
  -H "Content-Type: application/json" 
  -d '{"name":"Alice Updated"}'

Delete her:

curl -X DELETE http://localhost:4280/api/users/{id}

Returns 204 No Content. Hit the list endpoint again, and she’s gone. Actually gone — not hidden behind a flag, not soft-deleted. The state changed.

This matters because your frontend code probably has flows like “create an item, see it appear in the list, edit it, see the edit reflected, delete it, confirm it’s removed.” With a stateless mock server, you can’t test that flow without faking it client-side. With stateful resources, the mock server behaves like a real backend.

Seed data from config

For repeatable test scenarios, you don’t want to start from an empty state every time. A YAML config file lets you pre-load data:

version: "1.0"
statefulResources:
  - name: products
    basePath: /api/products
    idField: id
    seedData:
      - id: "prod-001"
        name: "Widget"
        price: 9.99
        inStock: true
      - id: "prod-002"
        name: "Gadget"
        price: 24.99
        inStock: false

Start the server with mockd serve --config mockd.yaml, and those two products exist immediately. Your tests can rely on prod-001 being there without creating it first.

Multiple resources

Nothing stops you from running several resources at once. A typical setup might look like:

mockd add --path /api/users --stateful users
mockd add --path /api/products --stateful products
mockd add --path /api/orders --stateful orders

Three independent CRUD APIs, all on the same server, all holding their own state. Create a user, create a product, create an order that references both — the data is there for as long as the server is running.

Resetting state

During test runs, you usually want to start clean between scenarios. mockd lets you reset a resource back to its seed data (or back to empty, if there’s no seed data). This is useful in CI where you’re running the same test suite against the same mock server — you don’t want test A’s data leaking into test B.

What it doesn’t do

I want to be upfront about the boundaries here, because they matter:

No relational queries. You can’t JOIN users to orders. Each resource is an independent collection. If you create an order with userId: "abc123", mockd won’t check that a user with that ID actually exists. It stores what you give it — nothing more.

No field-level validation by default. POST any JSON shape you want to any resource, and mockd will accept it. Send {"favoriteColor": "blue"} to /api/users, and you’ll get back an object with favoriteColor, id, createdAt, and updatedAt. This is a feature — it stays out of your way while prototyping — but it also means mockd won’t catch schema mistakes for you.

State doesn’t survive server restart unless you use --data-dir to persist to disk. By default, everything lives in memory. Stop the server, and the data is gone. For most test and prototyping use cases this is fine — you want a clean slate anyway. But if you’re running mockd as a long-lived dev environment, pass --data-dir ./mock-data to keep state across restarts.

When I actually use this

The two scenarios where stateful resources save me the most time:

Frontend prototyping. I’m building a UI, the backend doesn’t exist yet, and I need more than static JSON. I need to create things, see them in lists, edit them, delete them. The full CRUD cycle. Stateful resources give me that in one command per entity.

Integration test fixtures. I seed the mock server with known data, run a test suite, then reset. The tests don’t depend on an external database or a staging environment that some other team might be deploying to at the same time.

It’s not a replacement for a real backend. It’s what you use until the real backend shows up — or when you need to test against something predictable that you fully control.

If you run into a case where stateful resources don’t quite fit — or you need something like filtering or pagination beyond the basics — open an issue. What gets built next depends a lot on what people actually ask for.

Learn more

Links

#stateful-mocking#testing#api-mocking#crud#mock server

Try mockd

Multi-protocol API mock server. HTTP, gRPC, GraphQL, WebSocket, MQTT, SSE, SOAP.

curl -fsSL https://get.mockd.io | sh