MSW (Mock Service Worker) is a library for mocking requests to actual production URI.
- Server-less. Doesn't establish any servers, operates entirely in a browser;
- Deviation-free. Request the very same resources (urls) you would in production, and let MSW intercept them and mock their responses;
- Mocking as a tool. Enable/disable/change mocking logic on runtime instantly without any compilations or rebuilds. Control the MSW lifecycle from your browser's DevTools;
- Essentials. Mock status codes, headers, delay responses, and create custom response mocking functions.
There are several points that I find annoying when conducting API mocking with any solution I've found:
- Often relies on a separate mocking server which you need to run and maintain;
- Doesn't really mock requests, rather replaces their urls to point to a mocking server, instead of a real server;
- Brings extra dependencies to your application, instead of being a simple dependency-free development tool.
This library annihilates those problems, as it takes an entirely different approach to the client-side API mocking.
MSW uses a Service Worker with its ability to intercept requests for the purpose of caching. Only, instead of caching MSW matches a dispatched request against a mocking schema, and returns a pre-defined mocked response upon match.
The primary benefit of using Service Workers for mocking is the ability to request the very same resources a client would in production. Since MSW performs "request-response" matching, there is no need for you to define conditional request URLs for the sake of mocking. It's enough to enable/disable the MSW to control if the mocking should happen.
A mocking function contains information about the request, so you can perform a real request and then patch it with the mocked data, if needed.
MSW uses conventional path definitions (as Express), making it ease to filter which outgoing traffic you want to mock. Requests not matching any mocking definition are bypassed and performed as if it was production.
npm install msw --save
Run the following command in your project's public directory:
node_modules/.bin/msw init <publicDir>
Replace
publicDir
with the relative path to your server's public directory (i.e.msw init ./public
).
This copies the mockServiceWorker.js
file to the specified publicDir
, so it's served as a static asset by your server. This way browser can access and register the mock service worker module.
A public directory is usually a build directory of your application (./build
, ./public
or ./dest
). It's the root directory served by your server. This directory is often committed to Git, so should be the Mock Service Worker.
You may also generate the Mock Service Worker as a part of your build.
Start by creating a mocking definition file:
// app/mocks.js
import { composeMocks, rest } from 'msw'
// Configure mocking routes
const { start } = composeMocks(
rest.get('https://api.github.com/repo/:repoName',
(req, res, { status, set, delay, json }) => {
// access request's params
const { repoName } = req.params
return res(
// set custom status
status(403),
// set headers
set({ 'Custom-Header': 'foo' }),
// delay the response
delay(1000),
// send JSON response body
json({ errorMessage: `Repository "${repoName}" not found` }),
)
)
)
/* Start the Service Worker */
start()
Modularize, abstract, reuse. The structure of mocks is up to you, but be sure to call
start()
only once.
Mocking is a development-only procedure. It's recommended to include your mocking module (i.e. app/mocks.js
) into your application's entry during the build. See the examples below.
// ./webpack.config.js
const __DEV__ = process.env.NODE_ENV === 'development'
module.exports = {
entry: [
// Include mocks when in development
__DEV__ && 'app/mocks.js',
// Include your application's entry
'app/index.js',
].filter(Boolean),
// Rest of your config here
...webpackConfig,
}
Alternatively, you can require mocking file(s) conditionally in your client bundle.
// app/index.js
if (process.env.NODE_ENV === 'development') {
require('./mocks.js')
}
Service Workers are designed as a caching tool. However, we don't want our mocking definitions to be cached since that would result into out-of-date logic during development.
It's highly recommend to enable "Update on reload" option in your browser (DevTools > Application > Service Workers, in Chrome). This will force Service Worker to update on each page reload, ensuring the latest logic is applied.
Read more about the Service Worker Lifecycle.
MSW (Mock Service Worker) uses Service Worker API with its primary ability to intercept requests, but instead of caching responses it imitates them according to the provided mock definitions. Here's a simplified internal flow:
- MSW spawns a dedicated Service Worker and creates a communication channel between the worker and the client.
- Service Worker then signals any outgoing requests on the page to the MSW, which attempts to match them against the defined mocking routes.
- When any match occurs, the
resolver
function is executed, and its payload is returned as the mocked response.
This library is meant to be used for development only. It doesn't require, nor encourage you to install any Service Worker on production environment.
Composes given mocking definitions into a single schema.
import { composeMocks, rest } from 'msw'
const { start } = composeMocks(
rest.get('https://api.github.com/users/:username', resolver),
rest.post(/api.backend.dev/, resolver),
)
Mock definitions exposed under the
rest
namespace contain high-order function convenient for mocking a REST API.
Have an idea? Found a bug? Please communicate it through using the issues tab of this repository. Pull requests are welcome as well!