- Introduction
- Getting started
- Philosophy
- Comparison
- Limitations
- Debugging runbook
- FAQ
- Basics
- Concepts
- Network behavior
- Integrations
- API
- CLI
- Best practices
- Recipes
- Cookies
- Query parameters
- Response patching
- Polling
- Streaming
- Network errors
- File uploads
- Responding with binary
- Custom worker script location
- Global response delay
- GraphQL query batching
- Higher-order resolver
- Keeping mocks in sync
- Merging Service Workers
- Mock GraphQL schema
- Using CDN
- Using custom "homepage" property
- Using local HTTPS
Describing REST API
Learn how to describe REST API with Mock Service Worker.
Import
MSW provides a designated http namespace for describing HTTP requests. We will use that namespace to describe what requests to intercept and how to respond to them.
http namespace from the msw package:// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = []Although GraphQL is often implemented over HTTP, we highly recommend using the designated
graphqlnamespace for describing GraphQL APIs.
Request handler
Next, we will create a Request handler. Every method in the http namespace allows us to create a request handler corresponding to an HTTP request method:
http[method](predicate, resolver)Request handlers are functions that allow you to Intercept requests and Mock responses.
In this tutorial, we will describe a basic RESTful API that has the following endpoints:
GET /posts, to return all existing posts;POST /posts, to create a new post;DELETE /posts/:id, to delete a post by ID.
Let’s start by creating a request handler for the GET /posts requests.
http.get() to declare your first request handler// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = [
// By calling "http.get()" we're instructing MSW
// to capture all outgoing "GET /posts" requests
// and execute the given response resolver when they
// happen.
http.get('/posts', () => {
// Response resolver allows you to react to captured requests,
// respond with mock responses or passthrough requests entirely.
// For now, let's just print a message to the console.
console.log('Captured a "GET /posts" request')
}),
]Note that you can also provide an absolute request URL to intercept requests
to external services, like http.get('https://example.com/resource').
Following the same principle, add request handlers for the remaining endpoints:
// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = [
http.get('/posts', () => {
console.log('Captured a "GET /posts" request')
}),
http.post('/posts', () => {
console.log('Captured a "POST /posts" request')
}),
http.delete('/posts/:id', ({ params }) => {
console.log(`Captured a "DELETE /posts/${params.id}" request`)
}),
]With these handlers defined, MSW will intercept the respective requests but won’t do anything to respond to them just yet.
Response resolver
Response resolver is the second argument to the request handler that decides how to handle the intercepted request. There are multiple things you can do with such a request: respond with a mock response, perform it as-is, perform a proxy request and augment the original response, etc. You can always learn more about response resolver on this pages:
Response resolver
Learn more about response resolvers.
Mocking responses
Learn how to mock HTTP responses.
In this tutorial, we will be responding to the intercepted requests with mock responses.
Mocking responses
To respond to an intercepted request, construct a valid Fetch API Response instance and return it from the corresponding request handler. Although you can work with the Response instance directly, we highly recommend using the HttpResponse class provided by the library.
HttpResponse class from msw:import { http, HttpResponse } from 'msw'Learn about what
HttpResponseis and why you should use it over the standardResponsein here.
Next, let’s construct the mocked response to return the list of all posts.
HttpResponse from the GET /posts resolver:// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
// Let's keep a map of all existing posts in memory.
// At the beginning, this list is empty as we have no posts.
const allPosts = new Map()
export const handlers = [
http.get('/posts', () => {
// Construct a JSON response with the list of all posts
// as the response body.
return HttpResponse.json(Array.from(allPosts.values()))
}),
// ...the other request handlers.
]Using the HttpResponse.json() static method, we are returning an application/json response from this resolver to be used as the mocked response.
Reading request body
In the POST /posts handler, let’s read the request body and push the new post to the allPosts map. We can get the reference to the intercepted request instance as the request argument to the response resolver function.
request argument:// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
const allPosts = new Map()
export const handlers = [
http.post('/posts', async ({ request }) => {
// Read the intercepted request body as JSON.
const newPost = await request.json()
// Push the new post to the map of all posts.
allPosts.set(newPost.id, newPost)
// Don't forget to declare a semantic "201 Created"
// response and send back the newly created post!
return HttpResponse.json(newPost, { status: 201 })
}),
]Reading path parameters
Lastly, let’s implement the DELETE /posts/:id resolver that will lookup and delete a post from allPosts by its ID. The path parameters of the request URL are parsed and stored as the params argument to the response resolver function.
id path parameter using the params argument// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
const allPosts = new Map()
export const handlers = [
http.delete('/posts/:id', ({ params }) => {
// All request path params are provided in the "params"
// argument of the response resolver.
const { id } = params
// Let's attempt to grab the post by its ID.
const deletedPost = allPosts.get(id)
// Respond with a "404 Not Found" response if the given
// post ID does not exist.
if (!deletedPost) {
return new HttpResponse(null, { status: 404 })
}
// Delete the post from the "allPosts" map.
allPosts.delete(id)
// Respond with a "200 OK" response and the deleted post.
return HttpResponse.json(deletedPost)
}),
]Response resolver provide you with much more useful data about the intercepted request, such as request cookies, GraphQL query and variables, and more. Learn more about the Response resolvers to unlock their full potential.
Reading request cookies
Access the parsed value of the request’s Cookie header as the cookies key on the response resolver object argument:
http.get('/user', ({ cookies }) => {
const { session } = cookies
if (!session) {
return new HttpResponse(null, { status: 401 })
}
})Next steps
Integrations
Once you have described the network you want, integrate it into any environment in your application.
Browser
Integrate MSW in a browser environment, such as a React application or Storybook.
Node.js
Integrate MSW in Node.js, such as an Express application or a test runner.
Recipes
Learn about other ways to work with requests and responses by browsing our recipes.