MSW — API Mocking of the Next Generation
Mock Service Worker intercepts network requests at the service worker layer, letting you mock REST and GraphQL APIs for tests and development without stubbing fetch. The same mocks work in Node, jsdom, browsers, and React Native.
What it is
Mock Service Worker (MSW) intercepts network requests at the service worker layer in the browser and at the request module level in Node.js. You define request handlers that describe how to respond to specific API calls, and MSW intercepts matching requests without modifying your application code. The same mocks work across unit tests, integration tests, Storybook, and local development.
MSW targets frontend developers who need to mock API endpoints for testing and development. It works with any HTTP client (fetch, axios, ky) and any framework (React, Vue, Angular, Svelte).
How it saves time or tokens
Traditional API mocking involves stubbing fetch or axios at the module level, which breaks when you switch HTTP clients or test implementation details. MSW operates at the network level, so your application code makes real fetch calls that are intercepted transparently. This means your tests exercise the actual HTTP layer and your mocks are reusable across testing environments.
How to use
- Install MSW:
npm install msw --save-dev. - Define request handlers in a
handlers.tsfile usinghttp.get(),http.post(), etc. - Set up the browser worker with
npx msw init public/ --saveor the Node server for tests.
Example
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/user', () =>
HttpResponse.json({ id: 1, name: 'Alice' })
),
http.post('/api/login', async ({ request }) => {
const body = await request.json();
if (body.password === 'secret') {
return HttpResponse.json({ token: 'abc123' });
}
return new HttpResponse(null, { status: 401 });
}),
];
// src/mocks/server.ts (for Node/test environment)
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
Related on TokRepo
- Testing Tools -- API mocking and test utilities
- Coding Tools -- Frontend developer tools
Common pitfalls
- Forgetting to call
server.listen()in test setup andserver.close()in teardown. Without these, MSW does not intercept requests. - Not running
npx msw init public/for browser environments. The service worker script must be in your public directory. - Defining handlers that are too specific (exact URL with query params) when you want to catch all variations. Use URL patterns or regex for flexible matching.
Frequently Asked Questions
Yes. MSW provides `setupServer` from `msw/node` that intercepts outgoing HTTP requests in Node.js without a service worker. This works with Jest, Vitest, Playwright, and any Node-based test runner.
Yes. MSW provides `graphql.query()` and `graphql.mutation()` handlers that match GraphQL operations by name. You can return typed responses and simulate errors for specific operations.
Nock patches Node's http module directly and only works in Node. MSW uses service workers in the browser and module interception in Node, making the same handlers work in both environments. MSW also has a more modern API and supports GraphQL natively.
Yes. MSW integrates with Storybook via the msw-storybook-addon. You define handlers per story, and the service worker intercepts API calls made by the component. This lets you demo different API states (loading, error, empty) in Storybook.
Yes. MSW 2.0 supports ReadableStream responses, allowing you to mock server-sent events (SSE) and chunked transfer encoding. This is useful for testing real-time features like AI chat completions or live data feeds.
Citations (3)
- MSW GitHub— MSW intercepts requests at the service worker and Node module level
- MSW Documentation— Supports REST and GraphQL mocking with the same handler API
- MSW Blog— MSW 2.0 supports streaming responses and ReadableStream
Related on TokRepo
Discussion
Related Assets
NAPI-RS — Build Node.js Native Addons in Rust
Write high-performance Node.js native modules in Rust with automatic TypeScript type generation and cross-platform prebuilt binaries.
Mamba — Fast Cross-Platform Package Manager
A drop-in conda replacement written in C++ that resolves environments in seconds instead of minutes.
Plasmo — The Browser Extension Framework
Build, test, and publish browser extensions for Chrome, Firefox, and Edge using React or Vue with hot-reload and automatic manifest generation.