Mocking your GraphQL API

Mocking your GraphQL API is a common practice when developing and testing your application. It allows you to simulate the behavior of your API without making real network requests.

How to use?

Add it to your plugins:

gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
 
export const gatewayConfig = defineConfig({
  plugins: [
    useMock({
      mocks: [
        {
          apply: 'User.firstName',
          faker: '{{name.firstName}}'
        }
      ]
    })
  ]
})

The example above will replace the resolver of User.firstName with a mock that uses faker.js to generate a random name.

Custom mock functions for fields

You can also provide a custom function to generate the mock value for a field:

gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
import { fullName } from './user-mocks.js'
 
export const gatewayConfig = defineConfig({
  plugins: pluginCtx => [
    useMock({
      mocks: [
        {
          apply: 'User.fullName',
          custom: fullName
        }
      ]
    })
  ]
})

Custom mock functions for types

You can mock types with custom mock functions like below;

gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
import { user } from './user-mocks.js'
 
export const gatewayConfig = defineConfig({
  plugins: pluginCtx => [
    useMock({
      mocks: [
        {
          apply: 'User',
          custom: user
        }
      ]
    })
  ]
})
user-mocks.ts
export const mockFullName = () => {
  return `John Doe`
}

When defined manually, properties can return values either directly or through a method. This is useful when defining static mocks because a mock property will be called as many times as there are items in an array. Here’s an example on how this could be achieved:

user-mocks.ts
function* generateNames() {
  while (true) {
    yield 'John Doe'
    yield 'John Snow'
  }
}
 
const fullNames = generateNames()
 
export const fullName = () => fullNames.next().value

Mocking the lists

Hive Gateway generates two mocked items by default if the return type is a list. But this can be configured, as shown below:

type Query {
  users: [User]
}
type User {
  id: ID
  fullName: String
}
gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
 
export const gatewayConfig = defineConfig({
  plugins: pluginCtx => [
    useMock({
      mocks: [
        {
          apply: 'User.fullName',
          faker: '{{name.fullName}}'
        },
        {
          apply: 'Query.users',
          length: 3
        }
      ]
    })
  ]
})

Now query { users { id fullName } } query will return 3 of User item;

{
  "users": [
    { "id": "SOME_RANDOM_ID", "fullName": "John Doe" },
    { "id": "SOME_RANDOM_ID", "fullName": "Jane Doe" },
    { "id": "SOME_RANDOM_ID", "fullName": "The Other Doe" }
  ]
}

Stateful mocking

Hive Gateway supports GraphQL Tools’ Stateful Mocking feature. So you can have stateful mocking by using the store provided in the context context.mockStore;

Initialize store

When having a schema that returns a list, in this case, a list of users:

init-store.ts
import { MockStore } from '@graphql-hive/gateway'
 
export const store = new MockStore()
const users = [{ id: 'uuid', name: 'John Snow' }]
// Set individual users' data in the store so that they can be queried as individuals later on
users.forEach(user => {
  store.set('User', user.id, user)
})
 
// Populate the `users` query on the root with data
store.set('Query', 'ROOT', 'users', users)

Get from the store

You can implement the mock query field *ById declaratively like below:

type Query {
  user(id: ID): User
}
gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
import { store } from './init-store.js'
 
export const gatewayConfig = defineConfig({
  plugins: pluginCtx => [
    useMock({
      store,
      mocks: [
        {
          apply: 'Query.user',
          custom: (_, args) => store.get('User', args.id)
        }
      ]
    })
  ]
})

Mutate data in the store

type User {
  id: ID
  name: String
}
type Query {
  me: User
}
type Mutation {
  changeMyName(newName: String): User
  updateUser(id: ID, name: String): User
}
gateway.config.ts
import { defineConfig, useMock } from '@graphql-hive/gateway'
import { store } from './init-store.js'
 
export const gatewayConfig = defineConfig({
  plugins: pluginCtx => [
    useMock({
      store,
      mocks: [
        {
          apply: 'Query.me',
          custom: (_, args, context) => store.get('User', 'uuid')
        },
        {
          apply: 'Mutation.changeMyName',
          custom: (_, args, context) => {
            const user = store.get('User', 'uuid')
            user.name = args.newName
            store.set('User', 'uuid', user)
            return user
          }
        },
        {
          apply: 'Mutation.updateUser',
          custom: (_, args, context) => {
            const user = store.get('User', args.id)
            user.name = args.name
            store.set('User', args.id, user)
            return user
          }
        }
      ]
    })
  ]
})