RequestHandler

The base class for request handler implementation.

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 nameTypeDescription
infoobjectRequest handler information object.
resolverFunctionResponse resolver function to handle matching requests.
optionsobjectOptional. 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 nameTypeDescription
headerstringPublic string representation of this request handler.
callFramestringThe 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"

Methods

parse(args)

Parses the intercepted request to extract additional information for further request handler phases.

Argument nameTypeDescription
requestRequestIntercepted request instance.
contextobjectRequest 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 nameTypeDescription
requestRequestIntercepted request instance.
parsedResultobjectThe object returned from the parse() method.
contextobjectRequest 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 nameTypeDescription
requestRequestIntercepted request instance.
parsedResultobjectThe object returned from the parse() method.
contextobjectRequest resolution context.

log(args)

Prints a browser console message whenever this request handler has handled the intercepted request.

Argument nameTypeDescription
requestRequestIntercepted request instance.
responseResponseResponse instance returned from the resolver function.
parsedResultobjectThe 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 })
  }),
]