- 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
Intercepting requests
Learn how to intercept outgoing requests.
In order to send a mocked response for a request, we have to intercept that request first. In Mock Service Worker, request interception is performed by functions called request handlers.
A request handler function looks like this:
// Intercept an HTTP GET request which path
// matches the "predicate", and resolve it
// using the given "resolver" function.
http.get(predicate, resolver)
// A similar request handler for a GraphQL mutation.
graphql.mutation(predicate, resolver)
Learn more about Request handlers.
In the context of this page, we will focus on how request handlers enable us to intercept request, omitting the resolver
part for now. The way the request interception is done will differ based on the API type we are mocking, reflecting the domain language of that API.
HTTP requests
HTTP requests can be intercepted using the http
request namespace. Methods in that namespace represent HTTP methods (http.get()
, http.post()
, etc.) and have the same function call signature expecting two arguments:
predicate
(string | RegExp
), a request path predicate;resolver
, (Response resolver
), a function that decides how to handle an intercepted request.
For example, here’s a request handler for a GET /pets
request that returns a list of pets:
import { http, HttpResponse } from 'msw'
http.get(
// The "/pets" string is a path predicate.
// Only the GET requests whose path matches
// the "/pets" string will be intercepted.
'/pets',
// The function below is a "resolver" function.
// It accepts a bunch of information about the
// intercepted request, and decides how to handle it.
({ request, params, cookies }) => {
return HttpResponse.json(['Tom', 'Jerry', 'Spike'])
},
)
Learn more about the
http
request namespace.
HTTP request matching
The nature of the predicate
argument allows you to intercept HTTP requests by multiple criteria. Let’s take a closer look at all possible ways to write a request predicate.
Request pathname
When the predicate
argument is a string, only the requests whose pathname matches that string will be intercepted. This works the same for both relative and absolute URLs!
export const handlers = [
http.get('/pets', petsResolver),
http.post('https://api.github.com/repo', repoResolver),
]
Relative request URLs are resolved against the current location.origin
, if
present.
You can include special tokens in the request predicate string to intercept multiple requests at the same time. One of the most common tokens is a wildcard (*
), which matches any string in its place:
// Intercept all GET requests to "/user":
// - GET /user
// - GET /user/abc-123
// - GET /user/abc-123/settings
http.get('/user/*', userResolver)
Request pathname matching in MSW is using
path-to-regexp
library. Learn more about all the supported path tokens in its documentation.
When providing request pathnames, make sure to exclude any query parameters. Query parameters have no effect on resource identification and instead serve as the means to send additional information to the server. If MSW encounters a query parameter, it removes it and prints a warning that you should remove it too. The values of the query parameters is still available to you in the request.url
property in the response resolver.
Regular expression
You can use Regular expressions as the request path predicate. Only the request whose URL matches the provided expression will be intercepted. Utilize the dynamic nature of regular expressions to handle more advanced request matching scenarios.
// Intercept DELETE requests matching the regular expression.
// - DELETE /settings/sessions
// - DELETE /settings/messages
http.delete(/\/settings\/(sessions|messages)/, resolver)
GraphQL API requests
GraphQL servers are often implemented via HTTP so you can use the same http
request namespace to intercept and resolve them. However, MSW provides a first-class support for intercepting GraphQL APIs using a designated graphql
request namespace. Methods of that namespace represents GraphQL operation types (graphql.query()
, graphql.mutation()
) and have the same function call signature expecting the following arguments:
predicate
, (string | RegExp | TypedDocumentNode
);resolver
, (Response resolver
).
For example, here’s a request handler for a ListPets
query that returns a list of pets:
import { graphql, HttpResponse } from 'msw'
export const handlers = [
graphql.query('ListPets', () => {
return HttpResponse.json({
data: {
pets: [
{ id: 1, name: 'Tom' },
{ id: 2, name: 'Jerry' },
{ id: 3, name: 'Spike' },
],
},
})
}),
]
GraphQL request matching
By default, MSW matches all GraphQL requests, regardless of their endpoint, by their operation type and operation name. The easiest way to visualize it is to imagine an actual GraphQL query your application makes:
query ListPets {
pets {
id
name
}
}
In the query above, query
is the operation type while ListPets
is the operation name.
Let’s take a look at all possible ways to define a GraphQL request predicate.
GraphQL operation name
When the GraphQL request predicate is a string, only the operations whose name matches that string will be intercepted.
// Intercept GraphQL queries that match the provided name.
// - "query GetUser { ... }"
graphql.query('GetUser', userResolver)
Regular expression
Similar to the HTTP request matching, you can use Regular expressions to gain more control over what GraphQL operation names should be intercepted.
// Intercept GraphQL mutations that match the regular expression.
// - "mutation CreateUser { ... }"
// - "mutation CreateAuthor { ... }"
graphql.mutation(/(CreateUser|CreateAuthor)/, resolver)
Endpoint URL
In more advanced scenarios, you can narrow down the GraphQL request interception by binding it to a specific HTTP endpoint. This is particularly useful when you need to distinguish between same operation types/names that are performed against different GraphQL APIs in your application.
import { graphql } from 'msw'
const github = graphql.link('https://api.github.com/graphql')
const stripe = graphql.link('https://api.stripe.com')
export const handlers = [
github.query('GetUser', githubUserResolver),
stripe.query('GetUser', stripeUserResolver),
]
Learn more about the
graphql.link()
API.
Common questions
How do I use relative URLs in Node.js?
You don’t. In Node.js, there is nothing to be relative to. If you are describing a network behavior for a Node.js application, use the absolute URLs you are requesting. If you are using MSW with a Node.js-based test runner, like Jest or Vitest, configure those runners accordingly to support relative URLs (i.e. polyfill the window.location
object).