- Published on
- • 5 min read
GraphQL -Mutation query implementation - Ruby on Rails
- Authors

- Name
- Shaiju Edakulangara
- @eshaiju
Mutation is a special type of query used to change data in the database, such as creating, editing, or deleting records from a table or store. These are equivalent to POST, PUT, PATCH, and DELETE in HTTP/REST terminology. Defining mutations is very similar to defining queries. The only difference is how you implement the logic inside the mutation. In mutations, you can control and specify the output data that the API needs to return after the mutation procedure.
In this article, I am adding a mutation query to add comments to an article, which we discussed in the previous example.
To add mutations to your GraphQL schema, first we need to define a mutation type in the mutations folder:
# app/graphql/mutations/mutation_type.rb
MutationType = GraphQL::ObjectType.define do
name "Mutation"
end
Now we need to pass it into the schema:
# app/graphql/graphql_ruby_sample_schema.rb
GraphqlRubySampleSchema = GraphQL::Schema.define do
query QueryType
mutation MutationType
end
Like QueryType, MutationType is a root of the schema. Members of MutationType are mutation fields. For GraphQL in general, mutation fields are identical to query fields except that they have side-effects (which mutate application state, eg, update the database).
Since we created a new folder for mutations, we need to tell Rails to autoload the paths. Add the following code to application.rb to autoload it:
# config/application.rb
config.autoload_paths << Rails.root.join('app/graphql/mutations')
Now we need to define a specific mutation query. The following steps outline the process to define a mutation:
- Give the operation a name
- Declare its inputs
- Declare its outputs
- Declare the mutation procedure in the resolve block
The resolve block should return a hash with a key for each of the return_fields.
In our example, we need to define CommentMutations in mutations folder.
# app/graphql/mutations/comment_mutations.rb
# encoding: utf-8
module CommentMutations
Create = GraphQL::Relay::Mutation.define do
name "AddComment"
# Define input parameters
input_field :articleId, !types.ID
input_field :userId, !types.ID
input_field :comment, !types.String
# Define return parameters
return_field :article, ArticleType
return_field :errors, types.String
resolve ->(object, inputs, ctx) {
article = Article.find_by_id(inputs[:articleId])
return { errors: 'Article not found' } if article.nil?
comments = article.comments
new_comment = comments.build(user_id: inputs[:userId], comment: inputs[:comment])
if new_comment.save
{ article: article }
else
{ errors: new_comment.errors.to_a }
end
}
end
end
Here, input_field specifies the input parameters we can pass in the query. In return_field, we can specify the fields to return after the update. Inside the resolve block, we define the business logic. The resolve block should return a hash with a key for each of the return_fields.
After defining this, we need to add the mutation's derived field to the mutation type.
# app/graphql/mutations/mutation_type.rb
MutationType = GraphQL::ObjectType.define do
name "Mutation"
# Add the mutation's derived field to the mutation type
field :addComment, field: CommentMutations::Create.field
end
Now we can try this mutation in GraphiQL:
mutation addComment {
addComment(input: { comment: "New comment", articleId: 1, userId: 1 }) {
article {
id
comments {
comment
user {
name
}
}
}
}
}
Here’s a possible JSON response for that query:
{
"data": {
"addComment": {
"article": {
"id": 1,
"comments": [
{
"comment": "Good article",
"user": {
"name": "Shaiju E"
}
},
{
"comment": "New comment",
"user": {
"name": "Shaiju E"
}
}
]
}
}
}
}
We can call the same query by passing inputs using variables:
mutation addComment($comments: AddCommentInput!) {
addComment(input: $comments) {
article {
id
comments {
comment
user {
name
}
}
}
}
}
# Query Variables
{
"comments": {
"comment": "New comment1",
"articleId": 1,
"userId": 1
}
}
comments to take values from query variables section. **input: comments as input to mutation query.

Let's write another example for an update mutation. If we want to update a comment, we need to write an UpdateComment mutation in comment_mutations.rb.
# app/graphql/mutations/comment_mutations.rb
# encoding: utf-8
module CommentMutations
Update = GraphQL::Relay::Mutation.define do
name "UpdateComment"
# Define input parameters
input_field :id, !types.ID
input_field :comment, types.ID
input_field :userId, types.ID
input_field :articleId, types.ID
# Define return parameters
return_field :comment, CommentType
return_field :errors, types.String
resolve ->(object, inputs, ctx) {
comment = Comment.find_by_id(inputs[:id])
return { errors: 'Comment not found' } if comment.nil?
valid_inputs = ActiveSupport::HashWithIndifferentAccess.new(inputs.instance_variable_get(:@original_values).select { |k, _| comment.respond_to? "#{k}=".underscore }).except(:id)
if comment.update_attributes(valid_inputs)
{ comment: comment }
else
{ errors: comment.errors.to_a }
end
}
end
end
The main difference here is that we need to create valid_inputs. This will allow us to perform mass assignment with update_attributes using only the valid fields that we passed.
After defining this, we need to add the mutation's derived field to the mutation type.
# app/graphql/mutations/mutation_type.rb
MutationType = GraphQL::ObjectType.define do
name "Mutation"
# Add the mutation's derived field to the mutation type
field :addComment, field: CommentMutations::Create.field
field :updateComment, field: CommentMutations::Update.field
end
Mutation to delete a comment and return the post and deleted comment ID:
# app/graphql/mutations/comment_mutations.rb
# encoding: utf-8
module CommentMutations
Destroy = GraphQL::Relay::Mutation.define do
name 'DestroyComment'
description 'Delete a comment and return post and deleted comment ID'
# Define input parameters
input_field :id, !types.ID
# Define return parameters
return_field :deletedId, !types.ID
return_field :article, ArticleType
return_field :errors, types.String
resolve ->(_obj, inputs, ctx) {
comment = Comment.find_by_id(inputs[:id])
return { errors: 'Comment not found' } if comment.nil?
article = comment.article
comment.destroy
{ article: article.reload, deletedId: inputs[:id] }
}
end
end
# app/graphql/mutations/mutation_type.rb
MutationType = GraphQL::ObjectType.define do
name "Mutation"
# Add the mutation's derived field to the mutation type
field :addComment, field: CommentMutations::Create.field
field :updateComment, field: CommentMutations::Update.field
field :destroyComment, field: CommentMutations::Destroy.field
end
Now we can try this mutation in GraphiQL:
mutation destroyComment($comment: DestroyCommentInput!) {
destroyComment(input: $comment) {
errors
article {
id
comments {
id
comment
}
}
}
}
# Query Variables
{
"comment": {
"id": 3
}
}
You can see sample code here.