Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Mock GraphQL Resolvers for Frontend Development
When the backend is not ready, frontend teams can block on API dependencies. Apollo Server’s built-in mocking generates fake data for every field in the schema, letting UI developers build and test against a working GraphQL endpoint within minutes. You can start with auto-generated mocks and progressively replace them with custom resolvers as the schema stabilizes.
When to Use This
- Frontend and backend teams work in parallel on a new feature
- You need a running GraphQL API for demos or prototyping
- Testing UI components against realistic data shapes
Prerequisites
- An Apollo Server instance with a defined schema
@apollo/serverandgraphqlinstalled
Solution
1. Enable Built-in Mocking
// mock-server.ts
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
role: String!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
publishedAt: String!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
}
`;
const server = new ApolloServer({
typeDefs,
mock: true,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`Mock server ready at ${url}`);
Apollo auto-generates values based on scalar types: random strings for String, incrementing numbers for Int/ID, ISO timestamps for fields named like dates.
2. Customize Mocks with Preserves
import { ApolloServer } from '@apollo/server';
const mocks = {
ID: () => crypto.randomUUID(),
String: () => 'Lorem ipsum',
Int: () => Math.floor(Math.random() * 1000),
Boolean: () => Math.random() > 0.5,
};
const server = new ApolloServer({
typeDefs,
mock: { mocks },
});
3. Mock Specific Types and Fields
const mocks = {
User: () => ({
id: () => crypto.randomUUID(),
name: () => faker.person.fullName(),
email: () => faker.internet.email(),
role: () => faker.helpers.arrayElement(['admin', 'editor', 'viewer']),
}),
Post: () => ({
id: () => crypto.randomUUID(),
title: () => faker.lorem.sentence(),
content: () => faker.lorem.paragraphs(3),
publishedAt: () => faker.date.recent().toISOString(),
}),
Query: () => ({
users: () => Array.from({ length: 5 }, () => ({})),
posts: () => Array.from({ length: 10 }, () => ({})),
}),
};
const server = new ApolloServer({
typeDefs,
mock: { mocks },
});
4. Conditional Mocks Based on Field Name
const mocks = {
String: () => {
return 'Generic string';
},
};
// Use a custom mock resolver for name-based logic
const mockResolvers = {
User: () => ({
name: () => faker.person.fullName(),
email: () => faker.internet.email(),
}),
Post: () => ({
title: () => faker.lorem.sentence(5),
content: () => faker.lorem.paragraphs(3),
}),
};
const server = new ApolloServer({
typeDefs,
mock: { mocks: { ...mocks, ...mockResolvers } },
});
5. Toggle Mocking by Environment
const server = new ApolloServer({
typeDefs,
resolvers: process.env.NODE_ENV === 'production' ? realResolvers : undefined,
mock: process.env.MOCK_API === 'true',
});
// Or combine real resolvers with mock fallback
const server = new ApolloServer({
typeDefs,
resolvers: realResolvers,
mock: process.env.NODE_ENV === 'development'
? { mocks, preserveResolvers: true }
: false,
});
With preserveResolvers: true, Apollo uses your real resolvers where they exist and falls back to mocks for unimplemented fields.
How It Works
- Auto-mocking inspects the schema and generates a default value for each scalar — strings, numbers, booleans, and lists are populated automatically.
- Custom mock functions override the defaults per type or per scalar. A
Usermock returns an object with field-level generators. preserveResolverslets you mix real and mocked data. Fields with a resolver use the real implementation; fields without one use the mock.- Faker integration produces realistic data — names, emails, sentences, dates — so the UI looks and behaves like it would with real data.
Advanced: Mocking with Custom Scalars and Enums
When your schema uses custom scalars or enums, provide mock functions for them explicitly:
import { ApolloServer } from '@apollo/server';
const typeDefs = gql`
enum Role {
ADMIN
EDITOR
VIEWER
}
scalar Date
type User {
id: ID!
name: String!
role: Role!
createdAt: Date!
}
`;
const mocks = {
Date: () => new Date().toISOString(),
Role: () => faker.helpers.arrayElement(['ADMIN', 'EDITOR', 'VIEWER']),
User: () => ({
name: () => faker.person.fullName(),
role: () => faker.helpers.arrayElement(['ADMIN', 'EDITOR', 'VIEWER']),
createdAt: () => faker.date.past().toISOString(),
}),
};
const server = new ApolloServer({
typeDefs,
mock: { mocks },
});
Without custom scalar mocks, Apollo returns null for those fields, which can break the frontend if it expects a valid value.
Advanced: Mocking Pagination with Relay Connections
For schemas using Relay-style cursor pagination, mock the connection structure:
const mocks = {
Query: () => ({
users: () => {
const edges = Array.from({ length: 10 }, (_, i) => ({
node: {
id: `user-${i}`,
name: faker.person.fullName(),
email: faker.internet.email(),
},
cursor: `cursor-${i}`,
}));
return {
edges,
pageInfo: {
hasNextPage: true,
hasPreviousPage: false,
startCursor: 'cursor-0',
endCursor: 'cursor-9',
},
totalCount: 100,
};
},
}),
};
This lets the frontend test infinite scroll, load-more buttons, and cursor-based navigation without a real backend.
Variants
Mock with MSW (Mock Service Worker)
For frontend-only mocking without a running server, use MSW with a GraphQL handler:
import { graphql } from 'msw';
export const handlers = [
graphql.query('GetUsers', (req, res, ctx) => {
return res(
ctx.data({
users: Array.from({ length: 5 }, () => ({
id: crypto.randomUUID(),
name: faker.person.fullName(),
email: faker.internet.email(),
})),
})
);
}),
];
Seeded Mocks for Reproducible Tests
import { faker } from '@faker-js/faker';
faker.seed(12345);
const mocks = {
User: () => ({
name: () => faker.person.fullName(),
email: () => faker.internet.email(),
}),
};
With a fixed seed, every server start produces the same fake data — useful for snapshot tests.
Error Mocking
Simulate error responses to test error handling in the UI:
const server = new ApolloServer({
typeDefs,
mock: { mocks },
formatError: () => ({
message: 'Simulated server error',
extensions: { code: 'MOCK_ERROR' },
}),
});
// Or throw in a mock resolver
const mocks = {
Query: () => ({
user: () => { throw new Error('User not found'); },
}),
};
Best Practices
-
For a deeper guide, see Complete Guide to GraphQL Testing.
-
Use realistic data —
fakerproduces names, emails, and dates that look real, making UI reviews more effective -
Start with auto-mocks, then customize — get the server running with
mock: truefirst, then replace fields one by one -
Use
preserveResolversduring migration — keep real resolvers for implemented features while mocking the rest -
Seed faker in tests — fixed seeds make snapshot tests deterministic
Common Mistakes
- Mocking with empty strings — the UI may hide or collapse empty values, hiding layout bugs
- Not mocking list lengths — a list mock returning one item doesn’t test pagination or empty states
- Forgetting to disable mocks in production — use environment variables to toggle mocking
- Not testing error states — mock error responses to verify the UI handles them
FAQ
Q: Can I mock only part of the schema?
A: Yes. Use preserveResolvers: true and provide real resolvers for implemented fields. Apollo mocks only the fields without resolvers.
Q: How do I mock authentication? A: Mock the context to return a fake user, or bypass auth checks entirely in mock mode.
Q: Should I use Apollo mocking or MSW? A: Use Apollo mocking when you want a running server. Use MSW when you want client-side interception without a server.
Q: Can I mock subscriptions? A: Apollo’s built-in mocking does not support subscriptions. Use a custom PubSub with fake events for subscription testing.
How do I mock custom scalars and enums?
Provide mock functions for each custom scalar and enum in the mocks object. For example, Date: () => new Date().toISOString() and Role: () => faker.helpers.arrayElement(['ADMIN', 'EDITOR', 'VIEWER']). Without these, Apollo returns null for custom scalar fields.
Can I mock Relay-style cursor pagination?
Yes. Mock the edges, pageInfo, and totalCount fields in your connection type. Return an array of edge objects with node and cursor properties, and set hasNextPage to true to test load-more behavior in the UI.
How do I share mocks between tests and the dev server?
Export the mocks object from a shared module (e.g., src/mocks/index.ts). Import it in both your test setup and your dev server configuration. This ensures consistent fake data across test and development environments. Use faker.seed() in tests for deterministic output.
Related Resources
Build a GraphQL API with Apollo Server and TypeScript
How to build a production-ready GraphQL API using Apollo Server, TypeScript, and DataLoader to solve the N+1 query problem
RecipeAPI Mocking for Testing
Build reliable tests by mocking external APIs with WireMock, MockServer, and MSW to eliminate flakiness and test edge cases.
RecipeStructured GraphQL Errors with Extension Codes
Implement structured error handling in GraphQL with custom error classes, extension codes, and consistent error formatting for clients
GuideComplete Guide to GraphQL Testing
Test GraphQL APIs at every layer: unit tests for resolvers, integration tests for schema, E2E tests for operations. Covers mocking, fixtures, snapshot testing, and performance testing.
GuideGraphQL Federation in Production
Run federated GraphQL in production with confidence. Covers subgraph composition, gateway deployment, entity resolution, schema coordination, observability, and failure handling.
GuideComplete Guide to GraphQL Federation
Build unified GraphQL APIs across multiple services with Apollo Federation. Covers subgraphs, supergraph composition, entity resolution, and gateway deployment.