Skip to content
>_ TrueFileSize.com
·8 min read

Mocking REST APIs with JSON Fixtures

Frontend blocked on a backend that doesn't exist yet? Mock your APIs. This guide covers MSW, json-server, and fixture strategies using sample JSON files for users, products, and nested objects.

Why mock instead of wait

  • Frontend and backend work in parallel, not sequentially
  • Reproducible test fixtures for E2E and CI
  • Demo environments that don't depend on infra
  • Offline development

Option 1: MSW (Mock Service Worker)

Intercepts fetch/XHR at the network layer. Your app code stays unchanged.

import { http, HttpResponse } from 'msw';
import { setupWorker } from 'msw/browser';
import users from './users.json';

const handlers = [
  http.get('/api/users', () => HttpResponse.json(users)),
  http.get('/api/users/:id', ({ params }) => {
    const user = users.find((u) => u.id === Number(params.id));
    return user
      ? HttpResponse.json(user)
      : new HttpResponse(null, { status: 404 });
  }),
  http.post('/api/users', async ({ request }) => {
    const body = await request.json();
    return HttpResponse.json({ id: users.length + 1, ...body }, { status: 201 });
  }),
];

const worker = setupWorker(...handlers);
worker.start();

Option 2: json-server (zero-config CRUD)

# Download sample data from /data/json
curl -o db.json https://example.com/users-sample.json

npx json-server db.json --port 3001

# Get GET /users, POST /users, PATCH /users/1 — all working

Perfect for quick prototypes. Supports pagination, filtering, sorting, and full CRUD with zero code.

Sample fixtures

Download from our data library:

Pattern: typed fixtures

// fixtures/users.ts
export interface User {
  id: number;
  email: string;
  name: string;
  role: 'admin' | 'user';
}

export const users: User[] = [
  { id: 1, email: '[email protected]', name: 'Alice', role: 'admin' },
  { id: 2, email: '[email protected]', name: 'Bob', role: 'user' },
];

Type-safe fixtures mean your mocks stay aligned with your domain model. Rename a field in the User type, TypeScript flags every fixture that needs updating.

Testing error states

// Simulate 500 error
http.get('/api/flaky', () => {
  return new HttpResponse(null, { status: 500 });
}),

// Simulate slow network
http.get('/api/slow', async () => {
  await new Promise((r) => setTimeout(r, 3000));
  return HttpResponse.json({ ok: true });
}),

Scope: mocks for dev and tests, never prod

  • Disable MSW in production builds
  • Gate via env var: if (process.env.NEXT_PUBLIC_MOCK) worker.start()
  • Use real APIs in staging to catch integration bugs early

Related

For database-side mocking, see database seeding from SQL dumps. For general JSON samples, read sample JSON data for API testing.