Why use mocks in frontend development
Frontend development blocked waiting for backend is the most common anti-pattern in agile teams. Your 2-week sprint loses 5 days because the /users API isn't ready yet. Mocks unblock parallel work: frontend builds UI against fake data, backend implements real logic, they integrate at the end.
Tools like MSW (Mock Service Worker) intercept HTTP requests in development, returning mocks without touching production code. JSON Server spins up a complete REST API from a db.json file in 2 minutes. Faker.js generates realistic random data (names, emails, addresses) instead of 'User 1', 'User 2'.
Critical mistake: overly simplistic mocks. If your /users mock returns only {id, name}, and the real backend includes {role, permissions, lastLogin, avatar, settings}, your frontend explodes in production. Mocks must replicate real structure or you're a kamikaze.
Standard REST response structure
Well-designed APIs follow recognizable patterns. Paginated list: returns {data: [], meta: {total, page, perPage, totalPages}}. Without meta, frontend can't build correct pagination. Individual object: {data: {id, ...attrs}} or directly the object; both are valid, but pick one and maintain consistency.
For errors, HTTP 400/422 should include {errors: [{field: 'email', message: 'already exists'}]}. A generic error like {error: 'bad request'} is useless, frontend doesn't know which field to mark red. Stripe and GitHub APIs are gold references: each error has specific code, human message and docs link.
Timestamps always in ISO 8601 (2024-01-15T14:30:00Z), never Unix epoch or local formats. IDs as strings, not numbers (avoids precision issues in JavaScript with integers >53 bits). Relations as /users/123/posts or include with ?include=posts in sideload, never infinite nesting that blows up payload.
Mocks for edge cases and errors
Testing only the happy path is testing 30% of your app. You need mocks for: rate limiting (429 Too Many Requests with Retry-After header), expired authentication (401 with {code: 'token_expired'}), conflicts (409 when creating duplicate), failed validation (422 with array of errors per field).
Realistic cases you forget: empty responses (array without items), objects with null fields (avatar not set), large responses (list of 1000 products), slow responses (simulate 3s latency). If your app doesn't handle loading states or empty states, users see broken screens.
MSW allows conditions: return 200 for first 2 requests, then 429. Or return error 50% of the time to force your code to handle network inconsistency. In Cypress you can cy.intercept('/api/users').as('getUsers').wait('@getUsers') and control exact timing of each request.
Professional mocking tools and workflows
Development: MSW + Faker.js is the winning stack. MSW intercepts fetch/axios in browser without extra server, Faker generates realistic emails instead of test@test.com. Setup: npm i -D msw @faker-js/faker, run npx msw init public/, create handlers in src/mocks/handlers.ts.
Testing: Direct mock in unit tests (Jest/Vitest with jest.mock), but in E2E (Cypress/Playwright) use real network mocks. Playwright has route.fulfill() that intercepts any request and returns custom JSON. Advantage: test complete integration without live backend.
For large teams: Postman Mock Servers or Stoplight Prism generate mocks from OpenAPI spec. Design your API in Swagger, Prism spins up HTTP server with automatic examples. Backend and frontend share same contract, zero drift between expected and implemented. Costs initial setup but in 10+ dev teams saves weeks of 'oops, API changed and nobody told me'.