Resolve GraphQL Requests Against a Mock Schema in MSW

Share this video with your friends

Social Share Links

Send Tweet

Operation-based GraphQL mocking allows you to move fast without investing time into schemas or resolvers.

But, when integrating Mock Service Worker into an existing application, going schema-first can be advantageous. Here's how you can route every GraphQL request to be resolved against a GraphQL schema, mocked or real, and use mock resolvers to control individual types and fields.

Tutor: [0:00] MSW allows us to control the network on a simple request-response basis. This means that it will use the exact responses we return without any transformations unless we explicitly define them.

[0:12] In the case of GraphQL responses, the client will receive any JSON we send back, even if it contains the fields that the original query didn't request.

[0:20] On one hand, this means we can start with GraphQL instantly without having to define any schemas or resolvers. On the other, we don't get the fields filtering that we expect from an actual GraphQL server. To make our GraphQL handlers behave as the actual production server, we can resolve the intercepted queries against the GraphQL schema.

[0:39] First, let's import the GraphQL and buildSchema functions from the GraphQL package, which is the official implementation for GraphQL in JavaScript. To prevent a namespace collision, import GraphQL as executeGraphQL.

[0:54] Next, let's define our GraphQL schema. You can use an existing schema if you have one, or create a mock schema while prototyping. Let's create a schema variable and set its value to the result of the buildSchema function call. This will transform our schema definition into an abstract syntax tree that the GraphQL package expects.

[1:13] Next, we will write a GraphQL schema that defines the types movie, review, and user, as well as the reviews query that returns the list of movie reviews, all using the GraphQL schema definition language.

[1:26] Let's adjust our existing listReviews handler to resolve against the GraphQL schema we've defined. A great thing about this is that we'll use the native GraphQL functionality to do that by calling the executeGraphQL function.

[1:39] This function needs a schema argument and the source. The source is the actual query object sent from the client. Let's get that query object as the query key on the responseResolver argument and provide it as the source.

[1:55] Forward the variables of the intercepted GraphQL query so we can access them in the resolvers later. Finally, let's add the root value that will describe the resolvers for our schema.

[2:07] Right now, we only have a single query called reviews in our schema, so let's define a GraphQL resolver for it. This is a regular resolver function in GraphQL, so we can access things like the arguments object for this field.

[2:21] In this resolver, let's paste the review logic we've had before, which consists of looking up the movie by the given movieId argument and returning the list of movie reviews if they exist. The executeGraphQL function will return a promise, so let's await it.

[2:39] This promise resolves to an object containing the errors and data properties, representing the errors and the resolved data for this query, respectively. This is precisely what we need to send back to the client, so let's return a JSON response, including the errors and data from GraphQL.

[2:57] With these changes, we are still sending the right movie reviews to the client, but instead of resolving from mock data directly, we are implying GraphQL to actually resolve the intercepted query against our mock schema.

[3:10] This gives us a lot of flexibility. For example, if we decide to drop the rating field, all we have to do is adjust the query sent from the client and see that the mock response automatically reflects that and no longer includes the removed field in the payload.