Introduction to GraphQL mutations

In the previous post we learned about the basics of GraphQL and the mutations were left out.

This is because mutations are a different beast from object types.

What are mutations?

Mutations are the way to make a GraphQL call that will save, update or destroy a data in our server, therefore mutating our data.

Think in mutations as the POST, PUT, PATCH, DELETE endpoints of a REST API.

The difference here is that you send a mutation and specify what you want back, in other words, perform a mutation followed by a query in one API hit.

That is the same inversion that GraphQL has for queries, the client specifies what he needs back and not the opposite.

Example

See an example of creating a product:

mutation {  
  createProduct(input: {name: "iPhone 7", price: 649.0}) {
    id
    name
    price
  }
}

The response may be similar to:

{
  "data": {
    "createProduct": {
      "id": "42",
      "name": "iPhone 7",
      "price": 649
    }
  }
}

The difference from query calls is that you need to wrap the mutation in a mutation block because all GraphQL calls are implicitly wrapped in a query block unless you specify otherwise.

To implement a mutation in graphl-ruby, you need to implement the mutation:

# app/graphql/mutations/create_product.rb
Mutations::CreateProduct = GraphQL::Relay::Mutation.define do  
  name "CreateProduct"

  input_field :name, !types.String
  input_field :price, !types.Float

  return_type Types::ProductType

  resolve ->(obj, args, ctx) {
    Product.create!(
      name: args[:name],
      price: args[:price]
    )
  }
end  

Tip: Using an exclamation makes the input field required.

Pretty similar to Object Types with the difference that you specify the input fields and the return type.

This means that you are supposed to return a product on the resolve block and that product will be passed to the Types::ProductType, therefore allowing the client to specify the response shape of that product type.

And then you need to specify the entry point on your mutation type:

Types::MutationType = GraphQL::ObjectType.define do  
  name "Mutation"

  field :createProduct, Mutations::CreateProduct.field
end  

Do not confuse the mutation with the mutation type.

A mutation implements the mutation algorithm whereas mutation type specifies the mutation "endpoints".

The mutation type is pretty similar to the query type, the difference is that you specify, as you guessed, the mutation endpoints.

Observations

As you may already know, you can specify more than one query for the same GraphQL call.

That's also true for mutations, you are able to perform multiple updates in one call:

mutation {  
  account: updateAccount(input: {name: "Gabriel Sobrinho"}) {
    id
    name
  }

  product: updateProduct(input: {id: 42, price: 769}) {
    id
    name
    comments(order: "mostRecent", limit: 10) {
      id
      author
      body
    }
  }
}

All the benefits of reading apply as well, you may use a different response shape for mobile application and a denser response shape for desktop applications.

All the cons apply as well, be sure to read my previous post to understand them.

Cheers.