Custom request predicate

By default, MSW gives you the means to intercept requests based on their method and path (for HTTP requests) or their operation kind and name (for GraphQL requests). You can, however, create a custom matching logic to intercept requests based on other criteria, for example:

  • Intercept a request that has a foo query parameter;
  • Intercept a request that has a JSON request body with a bar property.

Let’s implement both of these custom request predicates.

Query parameter predicate

You can implement a custom request predicate using a higher-order resolver function. In the example below, we will create a withSearchParams function that will help us match requests that satisfy a custom predicate based on the request’s query parameters.

// withSearchParams.js
import { passthrough } from 'msw'
 
export function withSearchParams(predicate, resolver) {
  return (args) => {
    const { request } = args
    const url = new URL(request.url)
 
    if (!predicate(url.searchParams)) {
      return passthrough()
    }
 
    return resolver(args)
  }
}

The resolver argument is the actual response resolver we will specify upon usage. The logic around it determines when to call it, allowing for conditional response resolution.

We can then use the withSearchParams function instead of the response resolver anywhere we wish:

// handlers.js
import { http, HttpResponse } from 'msw'
import { withSearchParams } from './withSearchParams'
 
export const handlers = [
  http.get(
    '/user',
    withSearchParams(
      // Only match "GET /user" requests that have
      // the "userId" query parameter present.
      (params) => params.has('userId'),
      ({ request, params, cookies }) => {
        return HttpResponse.json({
          name: 'John Maverick',
        })
      }
    )
  ),
]

Request body predicate

Implementing a custom request body predicate is no different from the query predicate. We will create a withJsonBody function that will provide the matching logic and call the resolver conditionally.

// withJsonBody.js
import isEqual from 'lodash.isequal'
 
export function withJsonBody(expectedBody, resolver) {
  return async (args) => {
    const { request } = args
 
    // Ignore requests that have a non-JSON body.
    const contentType = request.headers.get('Content-Type') || ''
    if (!contentType.includes('application/json')) {
      return
    }
 
    // Clone the request and read it as JSON.
    const actualBody = await request.clone().json()
 
    // Compare two objects using "lodash".
    if (!isEqual(actualBody, expectedBody)) {
      return
    }
 
    return resolver(args)
  }
}
http.post(
  '/user',
  // Only match "POST /user" requests that have the
  // "id" property of their body equal to "abc-123".
  withJsonBody(
    {
      id: 'abc-123',
    },
    ({ request, params, cookies }) => {
      return HttpResponse.json({}, { status: 201 })
    }
  )
)

Advanced

For more advanced scenarios, consider implementing a custom request handler. You can do that by extending the RequestHandler class exported from the library.

RequestHandler

API reference for the `RequestHandler` class.