February 23, 2021

GraphQL Mutation vs Query – When to use a GraphQL Mutation

Khalil Stemmler

Khalil Stemmler

This post is part of the Introduction to GraphQL series. You may want to read the previous posts: “What is GraphQL? GraphQL introduction” and “What is a GraphQL Query? GraphQL query examples using Apollo Explorer

So far, we’ve covered what GraphQL is: a query language and a server-side runtime. But more importantly, GraphQL is the modern way to build declarative, efficient and performant APIs that developers love to work with.

In the last post, we learned about GraphQL queries and how to test querying your API with Apollo Explorer.

In this post, we’re going to spend some more time on the other GraphQL operation: mutations. We’ll cover what mutations are, how they compare to queries, and when to use them.

About GraphQL mutations

In GraphQL, there are only two types of operations you can perform: queries and mutations.

While we use queries to fetch data, we use mutations to modify server-side data.

If queries are the GraphQL equivalent to GET calls in REST, then mutations represent the state-changing methods in REST (like DELETE, PUT, PATCH, etc).

Mutation examples

Consider a pet shop GraphQL API.

A query to fetch all the pets from the app might look like this:

query GetAllPets {
  pets {
    name
    petType
  }
}

And then a mutation that adds a new pet might look a little something like this:

mutation AddNewPet ($name: String!, $petType: PetType) {
  addPet(name: $name, petType: $petType) {
    id
    name
    petType
  }
}

The AddNewPet mutation expects values for the name and petType variables. The request data for this mutation holds the following shape.

{
  "name": "Rover",
  "petType": "DOG"
}

In the mutation response, you could expect to see the following result.

{
  "data": {
    "addPet": {
      "id": 1
      "name": "Rover",
      "petType": "DOG"
    }
  }
}

Similarities & differences

Structure

Mutations look very similar to queries. If you’ll recall, the general structure of a GraphQL operation looks like this.

One true difference between a query and a mutation, at least structurally, is the operation type. We use the word query for queries and mutation for mutations.

Another important thing to note is that we signal the mutation we want to invoke by naming it exactly as it occurs within our server-side GraphQL API.

In the AddNewPet example, the name of the mutation is addPet.

mutation AddNewPet ($name: String!, $petType: PetType) { 
  addPet(name: $name, petType: $petType) { # mutation name
    name
    petType
  }
}

This means that within our GraphQL API type definitions, we’d have a field on the root Mutation object that looks like the following:

type Mutation {
  addPet (name: String!, petType: PetType): AddPetResult!
}

Server-side config (resolvers)

Server-side resolvers for mutations involve code that changes state in some way.

Here’s an example of what it might look like to add a new pet using a connection to a petsAPI data source.

const resolvers = {
  ...
  Mutation: {
    addPet: async (root, args, context) => {
      const { name, petType } = args;
      const newPet = await context.dataSources.petsAPI.addPet({ name, petType })
      return {
        id: newPet.id,
        name,
        petType
      }
    }
  }
};

Compare this to a resolver in a query where the only responsibility is to fetch the requested resource.

Again, like RESTful requests, there’s nothing stopping us from writing API code here that makes the mutation resolver behave more like a query. But by convention, we ensure mutation operations change state, and query operations fetch data.

Return data

You may have noticed that the mutation also returns data; this is another similarity between queries and mutations. However, it’s conventional to only return the relevant new data that was created.

Conclusion: Determining whether to use query or a mutation

The best way to determine whether you want to write a query or a mutation is to ask yourself if you’re fetching data (query) or if modifying state in the server (mutation).

More query examples:

  • GetPetByPetId, GetMyPets, GetPetStores

More mutation examples:

  • EditPet, RemovePet, GiveTreat, RemoveAllPets, Login, Logout

Written by

Khalil Stemmler

Khalil Stemmler

Read more by Khalil Stemmler