JSONPlaceholder: Great for GETs, Broken for CRUDs
JSONPlaceholder is the most popular mock API on the internet. It's fast, free, and requires zero setup. Millions of developers use it for prototyping and learning REST APIs.
But it has one critical limitation: it's read-only.
When you send a POST request to JSONPlaceholder, it returns a fake 201 response — but nothing is actually saved. Your next GET request returns the original data, unchanged. PUT and DELETE behave the same way: they acknowledge your request but don't persist anything.
This means you can't test: - Optimistic UI updates — Is my state management correctly updating after a POST? - CRUD workflows — Does my edit form actually persist changes? - Delete confirmation flows — Is the item really removed from the list? - Real-time dashboards — Does the data update when I add new entries?
You're testing that your app can send requests, but not that it correctly handles the responses from a real stateful backend.
Antimass Labs vs JSONPlaceholder: Feature Comparison
| Feature | JSONPlaceholder | Antimass Labs Stateful API |
|---|---|---|
| GET | ✅ Fixed data | ✅ Your custom data |
| POST | ⚠️ Fake (not persisted) | ✅ Real persistence |
| PUT | ⚠️ Fake (not persisted) | ✅ Real persistence |
| DELETE | ⚠️ Fake (not persisted) | ✅ Real persistence |
| Custom Data | No (fixed todos/posts/users) | Yes (paste any JSON) |
| Endpoint Cleanup | N/A (static) | Auto-cleanup after 24h |
| Authentication | None needed | None needed |
| Rate Limits | Unofficial limits | Generous limits |
| Pricing | Free | Free |
| Backed By | Static JSON file | Redis on Cloudflare Edge |
Real Stateful Persistence
When you POST to an Antimass Labs endpoint, the data is actually stored in a Redis instance on Cloudflare's global edge network. Your next GET request returns the updated dataset — including your additions, modifications, and deletions.
Here's a real workflow:
// 1. Create your endpoint with initial data
const endpoint = 'https://antimasslabs.com/api/mock/your-id';
// 2. GET — returns your initial JSON
const res1 = await fetch(endpoint);
const data1 = await res1.json();
console.log(data1.payload.length); // 3 items
// 3. POST — add a new item (ACTUALLY persisted)
await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 4, title: 'New Item', done: false })
});
// 4. GET again — the new item is REALLY there
const res2 = await fetch(endpoint);
const data2 = await res2.json();
console.log(data2.payload.length); // 4 items ← real persistence!
// 5. DELETE — remove an item (ACTUALLY removed)
await fetch(endpoint, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 2 })
});
// 6. GET again — item is REALLY gone
const res3 = await fetch(endpoint);
const data3 = await res3.json();
console.log(data3.payload.length); // 3 itemsUse Case: Prototyping a Todo App
Let's build a complete Todo app prototype using the Stateful API as our backend:
'use client';
import { useState, useEffect } from 'react';
const API = 'https://antimasslabs.com/api/mock/my-todos';
export default function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
// Fetch todos on mount
useEffect(() => {
fetch(API).then(r => r.json()).then(d => setTodos(d.payload || []));
}, []);
// Add todo (REAL persistence)
const addTodo = async () => {
const newTodo = { id: Date.now(), title: input, done: false };
await fetch(API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo),
});
setTodos([...todos, newTodo]);
setInput('');
};
// Delete todo (REAL persistence)
const deleteTodo = async (id) => {
await fetch(API, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id }),
});
setTodos(todos.filter(t => t.id !== id));
};
return (
<div>
<input value={input} onChange={e => setInput(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(t => (
<li key={t.id}>
{t.title}
<button onClick={() => deleteTodo(t.id)}>✕</button>
</li>
))}
</ul>
</div>
);
}Self-Cleaning by Design
Every Stateful API endpoint has a 24-hour TTL. After 24 hours, the endpoint and all associated data are automatically purged from Redis.
This is a feature, not a limitation:
- No orphaned mock servers — you'll never forget to clean up - No data leaks — test data doesn't persist beyond its useful life - Perfect for workshops and demos — create endpoints for a class, they clean themselves up overnight - CI/CD friendly — each test run gets fresh endpoints
For developers used to JSONPlaceholder's eternal read-only data, this is a paradigm shift. Instead of one shared, immutable dataset, you get disposable, writable, private sandboxes that behave like real backends.
Ready to try it? Open the Stateful API tool — no account needed, no setup required.