- 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
RequestHandler
The base class for request handler implementation.
This class is meant for creating custom request handlers. Please prefer using
the standard http
and graphql
namespaces before creating a custom request handler.
Call signature
import { RequestHandler } from 'msw'
export class CustomRequestHandler extends RequestHandler {
constructor() {
super(args)
}
}
The RequestHandler
class constructor expects a single args
object with the following properties:
Argument name | Type | Description |
---|---|---|
info | object | Request handler information object. |
resolver | Function | Response resolver function to handle matching requests. |
options | object | Optional. Request handler options. |
Request handler options
once
- Optional.
Boolean
.
When set to true
, marks this request handler as inactive after the first …
Properties
info
object
.
Information object about this request handler.
Property name | Type | Description |
---|---|---|
header | string | Public string representation of this request handler. |
callFrame | string | The top-most frame of this request handler’s call. Useful for debugging. |
The info
object on the request handler instance will also merge whatever object you provide as the info
argument to the RequestHandler
constructor.
class MyHandler extends RequestHandler {
constructor(method, path, resolver) {
super({
info: {
// Public representation of this request handler.
// This string will be used when logging the handler
// using the ".log()" method.
header: `${method} ${path}`,
// Additional info properties forwarded from the
// constructor arguments of this custom handler.
method,
path,
},
resolver,
})
}
}
const handler = new MyHandler('GET', '/user')
console.log(handler.info.method) // "GET"
console.log(handler.info.path) // "/user"
The info
object is meant for representing public information about the
request handler. Do not use this object for internal handler context. Instead,
declare whichever additional properties you need as private properties on the
custom request handler class.
Methods
parse(args)
Parses the intercepted request to extract additional information for further request handler phases.
Argument name | Type | Description |
---|---|---|
request | Request | Intercepted request instance. |
context | object | Request resolution context. |
extendResolverArgs(args)
Extends the response resolver argument object. Whichever object is returned from the extendResolverArgs()
method gets shallow-merged with the default response resolver argument object.
Argument name | Type | Description |
---|---|---|
request | Request | Intercepted request instance. |
parsedResult | object | The object returned from the parse() method. |
context | object | Request resolution context. |
predicate(args)
Decides whether the intercepted request should be handled by this request handler. The predicate()
method is expected to return a boolean.
Argument name | Type | Description |
---|---|---|
request | Request | Intercepted request instance. |
parsedResult | object | The object returned from the parse() method. |
context | object | Request resolution context. |
log(args)
Prints a browser console message whenever this request handler has handled the intercepted request.
Argument name | Type | Description |
---|---|---|
request | Request | Intercepted request instance. |
response | Response | Response instance returned from the resolver function. |
parsedResult | object | The object returned from the parse() method. |
Request phases
Whenever MSW intercepts a request, it will pass it to the request handler. The request handler will then process the request in phases listed in the following order:
Phase 1: Parsing
First, the intercepted request instance will be parsed using the parse()
method of the request handler. The parsing phase is designed to extract additional information from the request that is otherwise unavailable in the Fetch API Request
instance.
Let’s create a custom SearchParamsHandler
that will only handle requests whose search parameters will match the expected object.
// SearchParamsHandler.js
import { RequestHandler } from 'msw'
export class SearchParamsHandler extends RequestHandler {
constructor(expectedParams, resolver) {
super({
info: { header: JSON.stringify(expectedParams) },
resolver,
})
this.expectedParams = expectedParams
}
parse({ request }) {
// Extract search parameters from the intercepted request URL.
const searchParams = new URL(request.url).searchParams
// Expose the search parameters for the other handler's methods.
return {
searchParams,
}
}
}
Phase 2: Predicate
The next phase determines if the intercepted request should be handled by this request handler. The intercepted request instance and the parsing result returned from the parse()
method are passed to the predicate()
method of the request handler. The predicate method must return a boolean indicating whether this handler is meant to handle the intercepted request.
For example, let’s iterate on the custom SearchParamsHandler
request handler to only match the intercepted requests whose search parameters match the provided expectedParams
object.
// SearchParamsHandler.js
import { RequestHandler } from 'msw'
export class SearchParamsHandler extends RequestHandler {
constructor(expectedParams, resolver) {
super({
info: { header: JSON.stringify(expectedParams) },
resolver,
})
this.expectedParams = expectedParams
}
parse({ request }) {
const searchParams = new URL(request.url).searchParams
return {
searchParams,
}
}
predicate({ request, parsedResult }) {
const { searchParams } = parsedResult
// Iterate over the expected search parameters and
// make sure that the actual request matches them.
for (const [expectedParamName, expectedParamValue] of Object.entries(
this.expectedParams
)) {
if (searchParams.get(expectedParamName) !== expectedParamValue) {
return false
}
}
return true
}
}
Phrase 3: Resolution
If the request handler returned true
in the predicate phase, the resolution phase begins. The parent RequestHandler
class handles the request resolution by executing the provided resolver
function with the request
instance and whichever additional information returned from the extendResolverArgs()
method. The response returned from the resolver function is propagated to MSW and it applies it to the request.
Here’s an example of using the extendResolverArgs()
method to extract URLSearchParams
from the intercepted request’s URL and expose them as additional data on the response resolver argument.
// SearchParamsHandler.js
import { RequestHandler } from 'msw'
export class SearchParamsHandler extends RequestHandler {
constructor(expectedParams, resolver) {
super({
info: { header: JSON.stringify(expectedParams) },
resolver,
})
}
parse({ request }) {
const searchParams = new URL(request.url).searchParams
return {
searchParams,
}
}
predicate({ request, parsedResult }) {
/* Search params predicate here */
}
extendResolverArgs({ request, parsedResult }) {
return {
searchParams: parsedResult.searchParams,
}
}
}
// handlers.js
import { HttpResponse } from 'msw'
import { SearchParamsHandler } from './SearchParamsHandler'
export const handlers = [
new SearchParamsHandler({ id: 'abc-123' }, ({ request, searchParams }) => {
// The custom request handler exposes the reference to
// the "URLSearchParams" instance of the intercepted request
// so we can operate with it directly in the resolver.
const id = searchParams.get('id')
return HttpResponse.json({ id })
}),
]