Creating, updating and deleting
MockLab isn't a read-only mock — every resource supports a real write path. Writes don't change the generated data itself; each one is stored as a small override layered on top, which is what makes resetting a resource safe and complete.
Creating a record
POST to the collection endpoint with a JSON object body. The server always assigns the id —
if your body includes one, it's discarded in favor of the real one — and returns the created
record with a 201 status.
curl -X POST https://mocklab.dev/m/demo7k2m9x/products \
-H "Content-Type: application/json" \
-d '{"title": "Desk lamp", "price": "$34.00", "inStock": true}'const response = await fetch("https://mocklab.dev/m/demo7k2m9x/products", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Desk lamp", price: "$34.00", inStock: true }),
});
const created = await response.json(); // { id: "...", title: "Desk lamp", ... }Replacing a record with PUT
PUT to /m/{project-key}/{resource-name}/{id} replaces the entire record with your body — any
field you don't send is gone from the result, exactly like a real REST API's PUT semantics.
Returns 200 with the full replaced record.
await fetch(`https://mocklab.dev/m/demo7k2m9x/products/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Desk lamp", price: "$29.00", inStock: false }),
});Updating a record with PATCH
PATCH merges your body onto the record's current value — generated or already overridden —
so only the keys you send change. This is almost always what you want for an "edit one field"
form.
import { useMutation, useQueryClient } from "@tanstack/react-query";
function useUpdatePrice(productId) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (price) =>
fetch(`https://mocklab.dev/m/demo7k2m9x/products/${productId}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ price }),
}).then((res) => res.json()),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["products"] }),
});
}Deleting a record
DELETE the same single-record URL. Returns 204 with no body — the record no longer appears
in list results or in a direct GET by id.
await fetch(`https://mocklab.dev/m/demo7k2m9x/products/${id}`, { method: "DELETE" });What isn't validated
None of these write endpoints validate your body against the resource's field types — a mock
API's entire point is accepting whatever shape a client under active development happens to
send, without you having to keep a schema perfectly in sync first. The only requirement is that
the body is a JSON object for POST/PUT/PATCH. Send a field that doesn't exist in the
schema and it's stored and returned exactly as sent; send nothing for a field the schema defines
and, for PUT, it's simply absent from the result.
One caveat above 10,000 records
Single-record GET/PUT/PATCH/DELETE only work by id for records that already have an
override — either created via POST, or a plain generated record you've already written to at
least once. On a resource with more than 10,000 records, an id belonging to a plain,
never-touched generated record returns 404 on these routes, because finding which index an
arbitrary id belongs to would mean generating records until a match turns up — exactly the scan
the 10,000 cutoff exists to avoid. See How generation works for
the full explanation.