How to Mock GraphQL APIs with Fake JSON Data (Apollo & urql)

July 6, 2026

Mocking a GraphQL API is a different problem than mocking REST. There's no fixed set of URLs to intercept — every request hits the same single endpoint with a different query — so you match on the operation name instead of the path. Here's how to do it properly with both Apollo Client and urql, the two most common GraphQL clients.


Step 1: Generate the Fake Data First

Shape your mock response to match your actual GraphQL schema's return type — including nested fields your query selects. Build that structure in Dummy JSON Generator before writing any mock resolver code.

{
  "id": "42",
  "title": "Deep Work",
  "author": { "id": "7", "name": "Cal Newport" },
  "reviews": [{ "id": "1", "rating": 5, "comment": "Excellent." }]
}

Option A: Apollo Client's MockedProvider

Apollo ships a first-party testing utility, MockedProvider, that matches mocks to queries by comparing the query document and its variables exactly.

import { MockedProvider } from '@apollo/client/testing'
import { GET_BOOK } from './queries'
import bookFixture from './mock/book.json'

const mocks = [
  {
    request: { query: GET_BOOK, variables: { id: '42' } },
    result: { data: { book: bookFixture } },
  },
]

render(
  <MockedProvider mocks={mocks} addTypename={false}>
    <BookPage id="42" />
  </MockedProvider>
)

Gotcha: MockedProvider matches variables exactly — if your component sends an extra variable you didn't include in the mock, the match silently fails and the query hangs in a loading state. Set addTypename={false} unless your fixtures include __typename fields.


Option B: MSW with graphql.query / graphql.mutation

If you're using urql, Vue Apollo, or want the same mocking approach across REST and GraphQL, MSW's GraphQL handlers match by operation name instead of exact query text — often more forgiving for larger apps with many similar queries.

import { graphql, HttpResponse } from 'msw'
import bookFixture from './mock/book.json'

export const handlers = [
  graphql.query('GetBook', ({ variables }) => {
    return HttpResponse.json({ data: { book: bookFixture } })
  }),
]

This works identically whether your client is Apollo, urql, or a plain fetch call to a GraphQL endpoint, since MSW intercepts at the network layer rather than inside the client library.


Handling Pagination and Lists

GraphQL APIs commonly paginate with cursor-based connections. Generate a list of fake items, then slice it inside your handler based on the incoming after/first variables so your mock actually behaves like a real paginated resolver instead of always returning page one.

graphql.query('GetBooks', ({ variables }) => {
  const { first = 10, after = 0 } = variables
  const page = allBooks.slice(after, after + first)
  return HttpResponse.json({
    data: {
      books: {
        edges: page.map(b => ({ node: b })),
        pageInfo: { hasNextPage: after + first < allBooks.length },
      },
    },
  })
})

Testing GraphQL Errors

GraphQL returns errors inside a 200 OK response body rather than an HTTP error status — a detail that trips up mocks written by developers used to REST. Make sure your error-state mocks follow the same shape.

graphql.query('GetBook', () => {
  return HttpResponse.json({
    errors: [{ message: 'Book not found' }],
    data: null,
  })
})

Which Approach Should You Use?

  • Small app, only using Apollo Client?MockedProvider — no extra dependency.
  • Multiple clients, or want shared mocks across REST and GraphQL? → MSW's GraphQL handlers.
  • Testing pagination or complex resolvers? → MSW, since it can implement real logic instead of static fixtures.