CRUD API Example
This example demonstrates mockd’s stateful mocking feature to simulate a complete CRUD (Create, Read, Update, Delete) API.
Overview
Section titled “Overview”We’ll create a mock API for a task management system with:
- Tasks (main resource)
- Users (for assignment)
- Persistent state across requests
Configuration
Section titled “Configuration”Create tasks-api.json:
{ "server": { "port": 4280 }, "stateful": { "resources": { "users": { "collection": "/api/users", "item": "/api/users/{id}", "idField": "id", "autoId": true, "seed": [ {"id": 1, "name": "Alice", "email": "alice@example.com"}, {"id": 2, "name": "Bob", "email": "bob@example.com"} ] }, "tasks": { "collection": "/api/tasks", "item": "/api/tasks/{id}", "idField": "id", "autoId": true, "filtering": true, "seed": [ { "id": 1, "title": "Setup project", "description": "Initialize the project structure", "status": "done", "assigneeId": 1, "createdAt": "2024-01-10T09:00:00Z" }, { "id": 2, "title": "Write documentation", "description": "Create user documentation", "status": "in_progress", "assigneeId": 2, "createdAt": "2024-01-11T10:00:00Z" }, { "id": 3, "title": "Add tests", "description": "Write unit tests", "status": "todo", "assigneeId": null, "createdAt": "2024-01-12T11:00:00Z" } ] } } }, "mocks": [ { "name": "Health check", "matcher": { "method": "GET", "path": "/health" }, "response": { "statusCode": 200, "body": {"status": "ok", "timestamp": "{{now}}"} } } ]}Start the Server
Section titled “Start the Server”mockd start --config tasks-api.jsonAPI Operations
Section titled “API Operations”List All Tasks
Section titled “List All Tasks”curl http://localhost:4280/api/tasksResponse:
[ { "id": 1, "title": "Setup project", "status": "done", "assigneeId": 1, "createdAt": "2024-01-10T09:00:00Z" }, { "id": 2, "title": "Write documentation", "status": "in_progress", "assigneeId": 2, "createdAt": "2024-01-11T10:00:00Z" }, { "id": 3, "title": "Add tests", "status": "todo", "assigneeId": null, "createdAt": "2024-01-12T11:00:00Z" }]Filter Tasks
Section titled “Filter Tasks”# By statuscurl "http://localhost:4280/api/tasks?status=todo"
# By assigneecurl "http://localhost:4280/api/tasks?assigneeId=1"Get Single Task
Section titled “Get Single Task”curl http://localhost:4280/api/tasks/2Response:
{ "id": 2, "title": "Write documentation", "description": "Create user documentation", "status": "in_progress", "assigneeId": 2, "createdAt": "2024-01-11T10:00:00Z"}Create Task
Section titled “Create Task”curl -X POST http://localhost:4280/api/tasks \ -H "Content-Type: application/json" \ -d '{ "title": "Review PR", "description": "Review pull request #42", "status": "todo", "assigneeId": 1 }'Response:
{ "id": 4, "title": "Review PR", "description": "Review pull request #42", "status": "todo", "assigneeId": 1}Update Task
Section titled “Update Task”curl -X PUT http://localhost:4280/api/tasks/4 \ -H "Content-Type: application/json" \ -d '{ "title": "Review PR", "description": "Review pull request #42", "status": "in_progress", "assigneeId": 1 }'Partial Update (PATCH)
Section titled “Partial Update (PATCH)”curl -X PATCH http://localhost:4280/api/tasks/4 \ -H "Content-Type: application/json" \ -d '{"status": "done"}'Delete Task
Section titled “Delete Task”curl -X DELETE http://localhost:4280/api/tasks/4Response: 204 No Content
Verify deletion:
curl http://localhost:4280/api/tasks/4Response: 404 Not Found
User Operations
Section titled “User Operations”List Users
Section titled “List Users”curl http://localhost:4280/api/usersCreate User
Section titled “Create User”curl -X POST http://localhost:4280/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Charlie", "email": "charlie@example.com"}'State Management
Section titled “State Management”View Current State
Section titled “View Current State”curl http://localhost:4290/stateReset State
Section titled “Reset State”# Reset all statecurl -X DELETE http://localhost:4290/state
# Reset specific resourcecurl -X DELETE http://localhost:4290/state/tasksImport State
Section titled “Import State”curl -X POST http://localhost:4290/state \ -H "Content-Type: application/json" \ -d '{ "tasks": [ {"id": 1, "title": "Fresh task", "status": "todo"} ] }'With Persistence
Section titled “With Persistence”Enable file persistence so state survives restarts:
{ "stateful": { "resources": { ... }, "persistence": { "enabled": true, "file": "./state.json", "saveInterval": "10s" } }}Workflow Example
Section titled “Workflow Example”Simulate a complete workflow:
# 1. Create a new taskTASK=$(curl -s -X POST http://localhost:4280/api/tasks \ -H "Content-Type: application/json" \ -d '{"title": "New feature", "status": "todo"}')TASK_ID=$(echo $TASK | jq -r '.id')
# 2. Assign to usercurl -X PATCH http://localhost:4280/api/tasks/$TASK_ID \ -H "Content-Type: application/json" \ -d '{"assigneeId": 1}'
# 3. Start workcurl -X PATCH http://localhost:4280/api/tasks/$TASK_ID \ -H "Content-Type: application/json" \ -d '{"status": "in_progress"}'
# 4. Complete taskcurl -X PATCH http://localhost:4280/api/tasks/$TASK_ID \ -H "Content-Type: application/json" \ -d '{"status": "done"}'
# 5. Verifycurl http://localhost:4280/api/tasks/$TASK_IDIntegration with Tests
Section titled “Integration with Tests”JavaScript/Node.js
Section titled “JavaScript/Node.js”const API = 'http://localhost:4280/api';
describe('Tasks API', () => { beforeEach(async () => { // Reset state before each test await fetch('http://localhost:4290/state', { method: 'DELETE' }); });
test('create and list tasks', async () => { // Create task const createRes = await fetch(`${API}/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Test task', status: 'todo' }) }); const task = await createRes.json(); expect(task.id).toBeDefined();
// List tasks const listRes = await fetch(`${API}/tasks`); const tasks = await listRes.json(); expect(tasks).toHaveLength(1); expect(tasks[0].title).toBe('Test task'); });
test('update task status', async () => { // Create const createRes = await fetch(`${API}/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Task', status: 'todo' }) }); const { id } = await createRes.json();
// Update await fetch(`${API}/tasks/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: 'done' }) });
// Verify const getRes = await fetch(`${API}/tasks/${id}`); const task = await getRes.json(); expect(task.status).toBe('done'); });});Python
Section titled “Python”import requests
API = 'http://localhost:4280/api'ADMIN = 'http://localhost:4290'
def test_task_crud(): # Reset state requests.delete(f'{ADMIN}/state')
# Create task = requests.post(f'{API}/tasks', json={ 'title': 'Test task', 'status': 'todo' }).json() assert 'id' in task
# Read fetched = requests.get(f'{API}/tasks/{task["id"]}').json() assert fetched['title'] == 'Test task'
# Update requests.patch(f'{API}/tasks/{task["id"]}', json={ 'status': 'done' }) updated = requests.get(f'{API}/tasks/{task["id"]}').json() assert updated['status'] == 'done'
# Delete resp = requests.delete(f'{API}/tasks/{task["id"]}') assert resp.status_code == 204
# Verify deleted resp = requests.get(f'{API}/tasks/{task["id"]}') assert resp.status_code == 404Next Steps
Section titled “Next Steps”- Integration Testing - More testing patterns
- Stateful Mocking Guide - Full reference
- Admin API - State management API