LOGOMock Service Worker
  1. Getting Started
  2. Define mocks
  3. Mocking GraphQL API

Mocking GraphQL API

Pre-requisites

Since we will be working with a GraphQL API, we need to have a GraphQL client installed and configured in our application. We need that client primarily to dispatch queries and mutations. Please refer to the getting started steps of the respective client.

Install and configure a GraphQL client

Here are some GraphQL clients to consider:

Supported clients

Any GraphQL client that complies with the GraphQL operations specification can be used with Mock Service Worker. A client must dispatch requests with the following signature:

1interface GraphQLRequest {
2 query: string
3 variables?: Record<string, any>
4}
Some GraphQL clients append extra information to the request's payload. That information will be available in the response resolver function.

Imports

In our src/mocks/handlers.js file let's import the essentials we need for mocking a GraphQL API. They are grouped under the graphql namespace exposed by the library.

Import graphql from the msw package:

1// src/mocks/handlers.js
2import { graphql } from 'msw'

Request handler

To handle a GraphQL request we need to specify its operation kind (query/mutation).

In this tutorial we will be mocking a basic login flow for our user. This flow implies handling two operations:

  • Login mutation, to allow a user to log in,
  • GetUserInfo query, to return the information about the logged in user.

Create request handlers by calling graphql[OPERATION_KIND] and providing an operation name:

1// src/mocks/handlers.js
2import { graphql } from 'msw'
3
4export const handlers = [
5 // Handles a "Login" mutation
6 graphql.mutation('Login', null),
7
8 // Handles a "GetUserInfo" query
9 graphql.query('GetUserInfo', null),
10]

Response resolver

To respond to an operation using a mocked response we have to specify it using a response resolver function.

Response resolver is a function that accepts the following arguments:

  • req, an information about a matching request;
  • res, a functional utility to create the mocked response;
  • ctx, a group of functions that help to set a status code, headers, data, etc. on the mocked response.

In GraphQL we describe the expected response in a query/mutation declaration itself. Let's design the shape of our response for both operations:

1# Authenticates using a given username
2mutation Login($username: String!) {
3 login(username: $username) {
4 username
5 }
6}
1# Returns the information about the authenticated user
2query GetUserInfo() {
3 user {
4 username
5 firstName
6 }
7}

Provide response resolvers to the previously defined request handlers:

1// src/mocks/handlers.js
2import { graphql } from 'msw'
3
4export const handlers = [
5 // Handles a "Login" mutation
6 graphql.mutation('Login', (req, res, ctx) => {
7 const { username } = req.variables
8 sessionStorage.setItem('is-authenticated', username)
9
10 return res(
11 ctx.data({
12 login: {
13 username,
14 },
15 }),
16 )
17 }),
18
19 // Handles a "GetUserInfo" query
20 graphql.query('GetUserInfo', (req, res, ctx) => {
21 const authenticatedUser = sessionStorage.getItem('is-authenticated')
22
23 if (!authenticatedUser) {
24 // When not authenticated, respond with an error
25 return res(
26 ctx.errors([
27 {
28 message: 'Not authenticated',
29 errorType: 'AuthenticationError',
30 },
31 ]),
32 )
33 }
34
35 // When authenticated, respond with a query payload
36 return res(
37 ctx.data({
38 user: {
39 username: authenticatedUser,
40 firstName: 'John',
41 },
42 }),
43 )
44 }),
45]

Utilize things like sessionStorage, localStorage, or IndexedDB to handle more complex API scenarios and user interactions.

Some GraphQL clients (i.e. Apollo) may require you to include the __typename property on each individual type on the mocked response:

1ctx.data({
2 user: {
3 firstName: 'John',
4 lastName: 'Maverick',
5 __typename: 'User'
6 }
7})

Follow the response shape of your GraphQL client to ensure you produce a compatible mocked response.

Next step

The request handlers are complete, yet there is one last step to perform: integrate the mocking.

Integrate/docs/getting-started/integrate