socket.help
← Blog

Test complete frontend flows with a stateful CRUD mock API

Create realistic test records, exercise create and edit flows, restore seed data, and share a temporary CRUD API with clear access and lifecycle controls.

Why a fixed JSON response is sometimes not enough

A static mock works well when you need to render a list or check an error message. It becomes less useful when the interface lets someone add a task, change its status and delete it. Returning the same list after every request hides bugs: the UI may appear to save successfully even though its next read loses the change.

A stateful CRUD mock keeps a small collection behind an HTTP endpoint. Creating an item changes later reads, updating changes that item, and deleting makes it unavailable. That gives a frontend team a more realistic integration target before the application backend is ready. Keep static mocks for fixed response shapes, latency and failure cases; use a mutable collection when the interaction depends on earlier requests.

Begin with a deliberate, repeatable seed

Choose a short collection path such as /tasks and a JSON array of synthetic records. Include the field types your interface actually renders: a string title, a numeric priority, a boolean flag or a nested display object. Give records stable string IDs when you need recognizable routes; missing seed IDs receive deterministic values. Do not paste customer records into a shared testing service.

A useful seed contains a few distinct cases rather than hundreds of identical rows. A long name can expose layout problems; an empty optional value can exercise a fallback; different statuses can test filters in your application. The workbench validates seed structure before creation and shows the live records in a table after the endpoint is ready.

A minimal collection configuration
{
  "name": "Tasks API",
  "routes": [],
  "crud": {
    "path": "/tasks",
    "seed": [
      {
        "id": "task_1",
        "name": "Review the checkout",
        "status": "todo"
      }
    ]
  }
}

Exercise the same requests your application will send

GET on the collection returns data, total, limit, offset and revision. Request an item by appending its ID. POST adds a record and returns HTTP 201 with the created object, including a generated string ID when you omit one. PUT replaces the item’s fields, while PATCH merges top-level fields; nested objects are replaced as values rather than recursively merged. DELETE returns 204, and a later read returns 404.

Collection reads accept limit and offset, a case-insensitive q search across serialized record content, and a top-level sort field with order=asc or desc. This deliberately small contract is easy to use from a web application. It does not infer database filters, resolve relationships or execute a query language. Inspect the actual list response instead of assuming the API returns a bare array.

Choose private or public access consciously

A newly created API is private. Its caller credential belongs in X-Access-Token, supplied separately from the endpoint URL. Your management credential controls configuration, lifecycle and reset; it is not a replacement caller credential. Workspace owners can also use authorized workspace access. A public endpoint allows anyone who knows its address to mutate records, not just read the list.

A resource’s records are isolated from other mock resources. The endpoint still expires according to its lifecycle, and its stored data counts toward applicable resource and storage allowances. This makes it suitable for temporary demos and integration checks. It is not a durable database for an application that users depend on. Keep the configuration export in your own project when you need to recreate the environment.

Make concurrent edits visible

Two developers can read the same record and then submit different edits. Without a guard, a later replacement can silently discard the earlier change. Each collection has a revision that advances after successful mutations and resets. Send the revision you read in X-Mock-If-Revision when writing; if another request has changed the collection, the server returns 409 and the current revision.

The workbench uses this guard for record writes. A conflict keeps your draft available while refreshing the collection, allowing you to inspect the current record before trying again. The guard applies to the whole collection, so even an edit to a different item can trigger a refresh. That conservative behavior keeps the model understandable for a small temporary sandbox.

Turn a manual check into a reusable lifecycle test

The scenario action builds a five-step test that creates a temporary record, captures its generated ID, reads it, changes its status, deletes it and expects a 404 afterward. The configuration contains a declared-secret placeholder for private access, never the access token itself. Loading the draft does not send requests. Supply the caller credential separately and review the sequence before running it.

The normal successful sequence cleans up its own record. If a request fails and execution stops, the test record may remain; inspect the table and delete it or restore the seed. Reset intentionally discards all live changes, so coordinate with anyone sharing the endpoint. Hosted scenario runners require a public network destination and cannot target localhost Docker addresses; direct HTTP clients and the platform MCP caller can exercise local deployments.