Mastering API Testing with Mocking in TypeScript: An Intro to Mock Service Worker
A comprehensive guide to using Mock Service Worker (MSW) for API testing in TypeScript projects.

Dylan Britz
•
Hey fellow developers! 👋 If you’re diving into the front-end world and struggling with API testing, you’re about to discover your new best friend: Mock Service Worker (MSW). Trust me, this library is a game-changer for TypeScript projects!
What’s the Deal with API Mocking?
When building front-end applications, we’re constantly hitting APIs — but what happens when those APIs aren’t ready? Or when you need to test error states? That’s where mocking comes in!
Mock Service Worker stands out from traditional mocking solutions by intercepting actual network requests right at the browser or Node.js level. No more complicated setup or maintaining separate mock servers!
Why MSW Will Make Your Life Easier
Here’s why you should be excited about MSW:
- Works seamlessly in any environment — browser, Node.js, or testing frameworks
- Intercepts actual network requests giving you realistic testing scenarios
- Plays perfectly with TypeScript
- Reuse the same mocks everywhere
Getting Started with MSW
Let’s set up MSW in your project with these simple steps:
1. Install the package
npm install msw --save-dev
2. Create your mock handlers
First, make a directory for your mocks:
mkdir src/mocks
touch src/mocks/handlers.ts
Then define your API mocks in the handlers file:
import { rest } from 'msw';
export const handlers = [
rest.get('/api/user', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
id: 1,
username: 'john_doe',
email: '[email protected]',
})
);
}),
];
3. Set up the service worker
Create a browser setup file:
// src/mocks/browser.ts
import { setupWorker } from 'msw';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
Then activate it in your app’s entry point:
// src/index.tsx
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser');
worker.start();
}
4. For testing environments
// src/mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
In your test setup:
// setupTests.ts
import { server } from './mocks/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Level Up Your Mocking Game with TypeScript
One of the coolest things about MSW is how it leverages TypeScript’s power:
import { rest } from 'msw';
import { User } from './types'; // Your User interface
export const handlers = [
rest.get<{}, {}, User>('/api/user', (req, res, ctx) => {
return res(
ctx.json({
id: 2,
username: 'jane_doe',
email: '[email protected]',
})
);
}),
];
Pro Tips for MSW Success
Here are some tips I’ve learned from using MSW in production:
- Mock different response states — Success, errors, loading states
- Keep related endpoints together for better maintainability
- Combine MSW with Storybook to create component stories with realistic data flows
- Empty arrays, weird data formats, network timeouts — simulate it all!
- The more realistic your mocks, the more valuable your tests
Example of error state mocking:
rest.get('/api/users', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ message: 'Internal server error' }));
});
MSW vs. Traditional Mocking: Why MSW Wins
I’ve tried many mocking solutions, and MSW stands out because it:
- Provides realistic network behavior
- Works in both development and testing
- Requires minimal setup
- Supports TypeScript out of the box
No more flaky API calls!
Conclusion
Implementing MSW in your TypeScript projects will change how you approach development and testing. You’ll build more robust applications, catch bugs earlier, and spend less time wrestling with backend dependencies.
Start small — mock just one endpoint and see the difference it makes in your workflow. Then gradually expand your mocks as you get comfortable with the approach.
Happy coding! 🚀