Define a Create Mutation

Next, we need to tell GraphQL about the parameters that needs to be accepted for creating a new speaker.

Let’s split this into a separate file, that handles this mutation — create_speaker.rb. Instead of inheriting from GraphQL::Schema::Mutation we create a mutation base class Mutations::BaseMutation. Also group all the mutations in mutations folder.

require 'graphql'
module Mutations
class BaseMutation < GraphQL::Schema::Mutation
end
end
require 'graphql'
require_relative 'base_mutation'
class Mutations::CreateSpeaker < Mutations::BaseMutation
description 'Creates a speaker'
# input arguments for the mutation
# function to execute on mutation
end

It needs to accept all the fields for a speaker, which we created as strings in the DB. In GraphQL ruby, strings are represented with the String type, as defined in the gem.

require 'graphql'
require_relative 'base_mutation'
class Mutations::CreateSpeaker < Mutations::BaseMutation
description 'Creates a speaker'
argument :name, String, required: false
argument :bio, String, required: false
argument :twitter_handle, String, required: false
argument :talk_title, String, required: false
# ...
end

Next we need to take these fields and then call speaker.save with the defined input fields in the resolve function.

require 'graphql'
require_relative 'base_mutation'
class Mutations::CreateSpeaker < Mutations::BaseMutation
description 'Creates a speaker'
# input arguments
def resolve(name:, bio:, twitter_handle:, talk_title:)
speaker = Speaker.new(
name: name,
bio: bio,
twitter_handle: twitter_handle,
talk_title: talk_title
)
if speaker.save
{
success: true,
errors: []
}
else
{
success: false,
errors: speaker.errors.full_messages
}
end
end
end

This returns a hash with success and errors. We need to tell GraphQL about it as well. Note: errors is an array of Strings. We define these as “fields” in the mutation.

require 'graphql'
require_relative 'base_mutation'
class Mutations::CreateSpeaker < Mutations::BaseMutation
description 'Creates a speaker'
# input arguments
field :success, Boolean, null: false
field :errors, [String], null: false
# ...
# resolve function
# ...
end
end

Now the CreateSpeaker mutation is complete. It needs to be added to the root mutation — MutationType so that it gets included in the schema.

require 'graphql'
require_relative 'mutations/create_speaker'
class MutationType < GraphQL::Schema::Object
description "The mutation root of this schema"
field :createSpeaker, mutation: Mutations::CreateSpeaker
end
view raw mutation2.rb hosted with ❤ by GitHub

Restart the server with bundle exec puma.

If you use a client like GraphiQL, you should be able to see the docs in the right sidebar changes and now has a Mutation.

Add a new speaker, with the mutation and the query variables in the client.

mutation AddSpeaker($name:String, $talkTitle:String, $bio:String, $twitterHandle:String) {
createSpeaker(name: $name, talkTitle: $talkTitle, bio: $bio, twitterHandle: $twitterHandle) {
success
errors
}
}
{
"name": "Adam Smith",
"talkTitle": "Web Development Fundamentals",
"twitterHandle": "adamsm",
"bio": "Adam is a seasoned web developer, who has worked as a Software Engineer in Google, and now is the force behind the GraphiQL web client"
}
view raw variables.json hosted with ❤ by GitHub

Execute the mutation in the GraphiQL client. You should be able to see the response data json, with something like below:

GraphiQL Mutation Execution

The CreateSpeaker mutation has all the fields optional, but the Speaker model validates the presence of the name field. If you try to create a speaker without giving a name field, it will show up in errors return field.

We can avoid this validation at the schema level, by making the required argument mandatory. You just need to change null: false to the respective arguments.

module SpeakerMutations
Create = GraphQL::Relay::Mutation.define do
name 'CreateSpeaker'
description 'Creates a speaker'
input_field :name, !types.String # note the !
input_field :bio, types.String
input_field :twitterHandle, types.String
input_field :talkTitle, !types.String
# ... rest of the mutation body
end
end

Now the name and talk_title fields are non-nullable fields, and you’ll have to always give these fields when executing the mutation. Read about the type system in the official documentation.

Get notified on engineering articles like this

Follow us on twitter @neumeralhq