Mutations

In the last chapters you’ve learnt how to use GraphQL to read data. Time to add some. When you want to add data, you use almost the same syntax. How does the server know when you want to write data instead of reading? You have to use the mutation keyword instead of query. That’s all. Actually not all, but you will learn about the differences in this chapter.

Create an user

Let’s start with the mutation which adds a new user to the database, like in the howtographql.com common schema

mutation {
  createUser(name: String!, authProvider: AuthProviderSignupData!): User
}

input AuthProviderSignupData {
  email: AUTH_PROVIDER_EMAIL
}

input AUTH_PROVIDER_EMAIL {
  email: String!
  password: String!
}

It isn’t hard to imagine what this mutation does. The name suggests it matches our interest - it creates an user, takes two parameters of type String and AuthProviderSignupData and returns an User in response.

But wait… until now we’ve been using type not input. So what is this? input is a type that can be used as a parameter. You will frequently see it among mutations.

Let’s try to implement mutation in the following order:

  • Define case classes for inputs
  • Define InputObjectType’s for those classes,
  • Define ObjectType responsible for all Mutations
  • Tell a Schema to use this object.

Create case classes

Define InputObjectType’s

InputObjectType is to input what ObjectType is to the type keyword. It tells Sangria how to understand data. In fact you can define ObjectType and InputObjectType for the same case class, or even more than one. A good example is a User entity which consists of many fields. But if you need different data when you register a new user and during sign in, you can create different InputObjectType’s.

To avoid circular dependencies of types, like we’ve experiences in the last chapter ther a suggestion to use lazy keyword for every type. But in case above, AuthProviderEmail is nested object in AuthProviderSignupData which is built by macro. Thats why we had to add implicit we have to have this nested object type in the scope in the time of macro executing.

Define Mutation Object

It will be similar to the process you already know.

As you can see, we’re missing one function in DAO

Add Mutation to Schema

All mutations are optional so you have to wrap it in Some.

If you will try to run a server, you will get errors about unimplemented FromInput‘s. It’s an additional step we have to do to able run those mutations.

Provide FromInput for input classes

Sangria needs to read a part of JSON-like structure and convert it to case classes. That’s the reason why we need such FromInput type classes. There are two ways to do it, you can write your own mapper, but you can also use any JSON library to help with this process. In the first step we’ve added a dependency to the sangria-spray-json library, but if you want you can use any other library. Sangria uses this to convert it into proper FromInput type. All we need to do is to define a proper JSONReader for that case class and import some converting functions.

Everything should work as expected now.

Test case

Perform a query in graphQL console:

mutation addMe {
  createUser(
    name: "Mario",
    authProvider:{
      email:{
        email:"mario@example.com",
        password:"p4ssw0rd"
      }
    }){
    id
    name
  }
}

Of course you can use different data :)
If everything works, we can move forward and implement two more mutations.

AddLink mutation

Implement a mutation to able run a following code:

createLink(description: String!, url: String!, postedById: ID): Link

First try on your own, next compare to my solution.

Hint! You can skip creating case classes phase because we don’t need any of them. In this case parameters uses only String and Int which are simple scalars available out-of-the-box.

Also add a mutation’s definition inside the Mutation.fields sequence.

We’re missing arguments definitions

That’s all, now you should be able to run following query:

mutation addLink {
  createLink(
    url: "howtographql.com",
    description: "Great tutorial page",
    postedById: 1
  ){
    url
    description
    postedBy{
      name
    }
  }

}

Let’s implement the last mutation for voting:

Create mutation for voting

Add arguments needed by the next mutation and this mutation itself.

Add mutation definition.

We are done! You can test all those mutations in Graphiql console.

The current state of files changed in this chapter:

models/package.scala
DAO.scala
GraphQLSchema.scala


Now you know how to send data to the server. You will use this knowledge when we implement authentication and authorization logic in the next chapter.

Unlock the next chapter
What is a mutation?
It's a function which modify a context
It's a function responsible for authentication
It's a function executed before and after field
It's a complementor to Query but to update/put data instead of reading it