GraphQL Mutations in Apollo

Feb 13, 2020

A GraphQL mutation is an API operation that modifies data. Like Query, Mutation is a special type in your GraphQL schema:

const schema = `
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`;

Every member of the Mutation type is a distinct API operation that you can use to modify data. In the above schema, there is exactly one mutation: increment(). The increment() operation returns an object of type CountResult.

Implementing a Mutation

A GraphQL schema is just a list of type definitions. You also need to implement the business logic of the increment() mutation. Like for queries, you implement the increment() mutation as a resolver on the Mutation type:

const { ApolloServer, gql } = require('apollo-server');

let count = 0;

const schema = gql(`
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment: CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`);

const resolvers = {
  Query: {
    getCount: () => ({ count, time: Date.now() })
  },
  // `increment` is just a resolver for the Mutation type
  Mutation: {
    increment: () => ({ count: ++count, time: Date.now() })
  },
  CountResult: {
    count: obj => obj.count,
    time: obj => obj.time
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers });
const handle = await server.listen();

const axios = require('axios');
// Call the `increment` mutation
await axios.post(handle.url, {
  query: 'mutation { increment { count, time } }'
});

// After the `increment` mutation, `count` is now 1
const { data } = await axios.post(handle.url, {
  query: '{ getCount { count, time } }'
});

data.data; // { getCount: { count: 1, time: 1581442587371 } }

Note that, to actually call a mutation, you need to start your GraphQL query with the string 'mutation':

await axios.post(handle.url, {
  // Note 'mutation' below. Not necessary for queries, but
  // necessary for mutations.
  query: 'mutation { increment { count, time } }'
});

Mutation Arguments

A GraphQL mutation is a function like any other. You can pass arguments to your mutation as well. For example, if you want to allow increment() with a value other than 1, you can add a Number parameter to the increment() mutation:

const schema = `
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment(num: Int): CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`;

Apollo passes the arguments passed in to your mutation as the 2nd parameter to your mutation's resolver function:

increment: (obj, args) => {
  args.num; // Whatever the user passed in `increment()`
}

Below is a full implementation of increment() with arguments:

let count = 0;

const schema = gql(`
  type Query {
    getCount: CountResult
  }

  type Mutation {
    increment(num: Int!): CountResult
  }

  type CountResult {
    count: Int
    time: Float
  }
`);

const resolvers = {
  Query: {
    getCount: () => ({ count, time: Date.now() })
  },
  // `increment` is just a resolver for the Mutation type
  Mutation: {
    increment: (obj, args) => {
      count += args.num;
      return { count, time: Date.now() };
    }
  },
  CountResult: {
    count: obj => obj.count,
    time: obj => obj.time
  }
};

const server = new ApolloServer({ typeDefs: schema, resolvers });
const handle = await server.listen();

let axios = require('axios');
// Call the `increment` mutation with an argument. Note that
// GraphQL arguments are named: you need to put `num: 5`, not
// just `5`.
await axios.post(handle.url, {
  query: 'mutation { increment(num: 5) { count, time } }'
});

// After the `increment` mutation, `count` is now 5
const { data } = await axios.post(handle.url, {
  query: '{ getCount { count, time } }'
});

data.data; // { getCount: { count: 5, time: 1581442587371 } }

More Graphql Tutorials