Mocking
Mock your GraphQL data based on a schema.
📣 New in Apollo Server 4: Apollo Server 4 removes both the mocks
and mockEntireSchema
constructor options. This article has been updated to use the @graphql-tools
package to mock data for Apollo Server. For the most up-to-date information on @graphql-tools
, we recommend referencing their documentation.
Mocking enables Apollo Server to return simulated data for GraphQL operations based on your server's schema. The strongly-typed nature of a GraphQL API lends itself to mocking, which is an important part of a GraphQL-first development process.
Mocking enables frontend developers to build out and test UI components and features without needing to wait for a full backend implementation. Mocking is also valuable when using a UI tool like Storybook, because you don't need to start a real GraphQL server.
Enabling mocks
To mock data based on your schema start by installing the @graphql-tools/mock
and @graphql-tools/schema
packages into your dev dependencies:
npm install --save-dev @graphql-tools/mock @graphql-tools/schema
You can combine addMocksToSchema
(from @graphql-tools/mock
) and makeExecutableSchema
(from @graphql-tools/schema
) to provide mock data for every field in your server's schema:
import { ApolloServer } from '@apollo/server';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';import { typeDefs } from './schema';import { resolvers } from './resolvers';new ApolloServer({// addMocksToSchema accepts a schema instance and provides// mocked data for each field in the schemaschema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),}),});
import { ApolloServer } from '@apollo/server';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';import { typeDefs } from './schema';import { resolvers } from './resolvers';new ApolloServer({// addMocksToSchema accepts a schema instance and provides// mocked data for each field in the schemaschema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),}),});
Mocking logic looks at the type returned by each schema field and returns a default value for that type.
The table below covers the default scalar types and the default mocked values returned for each type:
Type | Default Mock Value |
---|---|
| Returns a random positive or negative integer. |
| Returns |
| Returns a random positive or negative double-precision floating-point value. |
| Randomly returns either |
| Returns a randomized UUID containing a combination of integers and letters. |
When using mocks, you don't have to specify resolvers
. By default, any resolvers
you specify are ignored when you enable mocks
. To configure this behavior, see Using existing resolvers with mocks.
Note: If typeDefs
has any custom scalar types, you will need to specify what your server should return for those types. You can do this by creating a customized mock with resolvers for each custom scalar type, as described below.
Customizing mocks
In the examples below, we use top-level await
calls to start our server asynchronously. Check out our Getting Started guide to see how we configured our project to support this.
For more sophisticated testing, you can customize your mocks to return user-specified data. You can customize your mocks by providing an object that specifies the values to return for different return types.
By default, the functions you define in your mocks
take precedence over any currently defined resolvers.
For example, below, both Query.hello
and Query.resolved
return Hello
:
import { ApolloServer } from '@apollo/server';import { startStandaloneServer } from '@apollo/server/standalone';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';const typeDefs = `#graphqltype Query {hello: Stringresolved: String}`;const resolvers = {Query: {resolved: () => 'Resolved',},};const mocks = {Int: () => 6,Float: () => 22.1,String: () => 'Hello',};const server = new ApolloServer({schema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),mocks,}),});const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });console.log(`🚀 Server listening at: ${url}`);
import { ApolloServer } from '@apollo/server';import { startStandaloneServer } from '@apollo/server/standalone';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';const typeDefs = `#graphqltype Query {hello: Stringresolved: String}`;const resolvers = {Query: {resolved: () => 'Resolved',},};const mocks = {Int: () => 6,Float: () => 22.1,String: () => 'Hello',};const server = new ApolloServer({schema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),mocks,}),});const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });console.log(`🚀 Server listening at: ${url}`);
You can also use mocks
to define object types and the fields belonging to those object types (much like a resolver map). In the below example, our mocked Person
object calls a function returning an object with fields that contain other functions:
// importing the casual libraryconst casual = require('casual');const mocks = {Person: () => ({name: casual.name,age: () => casual.integer(0, 120),}),};
// importing the casual libraryconst casual = require('casual');const mocks = {Person: () => ({name: casual.name,age: () => casual.integer(0, 120),}),};
This example uses casual, a fake data generator for JavaScript that returns a different result every time the function is called. In other scenarios, such as testing, a collection of fake objects or a generator that always uses a consistent seed are often necessary to provide consistent data.
Using lists in mocks
To automate mocking a list, return an array of the desired length. Using [...new Array(n)]
is convenient syntax for creating an array that contains n copies of undefined
.
import casual from 'casual';const mocks = {Person: () => ({// a list of length between 2 and 6, using the "casual" npm module// to generate a random integerfriends: [...new Array(casual.integer(2, 6))],// a list of three lists of two items: [[1, 1], [2, 2], [3, 3]]listOfLists: () => [...new Array(3)].map((i) => [...new Array(2)]),}),};
import casual from 'casual';const mocks = {Person: () => ({// a list of length between 2 and 6, using the "casual" npm module// to generate a random integerfriends: [...new Array(casual.integer(2, 6))],// a list of three lists of two items: [[1, 1], [2, 2], [3, 3]]listOfLists: () => [...new Array(3)].map((i) => [...new Array(2)]),}),};
Using existing resolvers with mocks
By default, mocks overwrite your server's existing resolvers. To use your server's resolvers while mocking, set the makeExecutableSchema
function's preserveResolvers
option to true
:
import { ApolloServer } from '@apollo/server';import { startStandaloneServer } from '@apollo/server/standalone';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';const typeDefs = `#graphqltype Query {hello: Stringresolved: String}`;const resolvers = {Query: {resolved: () => 'Resolved',},};const mocks = {Int: () => 6,Float: () => 22.1,String: () => 'Hello',};const server = new ApolloServer({schema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),mocks,preserveResolvers: true,}),});const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });console.log(`🚀 Server listening at: ${url}`);
import { ApolloServer } from '@apollo/server';import { startStandaloneServer } from '@apollo/server/standalone';import { addMocksToSchema } from '@graphql-tools/mock';import { makeExecutableSchema } from '@graphql-tools/schema';const typeDefs = `#graphqltype Query {hello: Stringresolved: String}`;const resolvers = {Query: {resolved: () => 'Resolved',},};const mocks = {Int: () => 6,Float: () => 22.1,String: () => 'Hello',};const server = new ApolloServer({schema: addMocksToSchema({schema: makeExecutableSchema({ typeDefs, resolvers }),mocks,preserveResolvers: true,}),});const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });console.log(`🚀 Server listening at: ${url}`);
Above, the resolved
query now uses its defined resolver, so it returns the string Resolved
.