Data Manipulation: A Dive into GraphQL Mutations in Rails 7 API

Dhyey Sapara
Simform Engineering
4 min readDec 20, 2023

Empowering your Rails 7 API with GraphQL Mutations: Transforming data management with ease

Graphql mutatation using rails api

In the previous part, we explored GraphQL, its advantages and disadvantages, and delved into queries and how to write and execute them. This part will focus on mutation — their purpose, composition, and use.

Mutation

Queries are responsible for fetching the data, but on the server side, we don’t only need fetching, but we should also be able to modify the data for this. We have the mutation.

There is a difference in the way the execution engine handles them: According to the specification, a GraphQL server must guarantee that mutations are executed consecutively, while queries can be executed in parallel.

Mutation Example:

mutation {
createBlog(input: {
title: "testing",
description: "testing the mutation",
user_id: 1
}) {
id
title
description
}
}

In this example, ‘createBlog’ creates a new blog with input arguments of title, description and user_id. The mutation then returns the id, title, and description of the newly created user.

Types of GraphQL Mutations

Mutations in GraphQL can be categorized into the following types:

  • Insert Mutations
  • Update Mutations
  • Delete Mutations

The above example was of insert mutation wherein we created a new blog. There’s also update mutation wherein we update the blog data, which is PUT/PATCH in REST and delete mutation where we specify the record to delete, which is DELETE in REST.

Insert Mutations

Let’s add insert mutation to create a blog for our project.

For generating mutation, graphql gem provides us with the following generator:

rails g graphql:mutation

But if you check all the generators provided, you will see that there’s also a create mutation generator, which we can use to generate create blog mutation. Run the following command:

rails g graphql:mutation_create blog

It will create a blog_create.rb file in the mutations folder, let’s modify it to:

# app/graphql/mutation/blog_create.rb
module Mutations
class BlogCreate < BaseMutation
description "Creates a new blog"

field :blog, Types::BlogType, null: false

argument :title, String, required: true
argument :description, String, required: true
argument :user_id, ID, required: true

def resolve(title:, description:, user_id:)
blog = Blog.new(title:, description:, user_id:)
raise GraphQL::ExecutionError.new "Error creating blog", extensions: blog.errors.to_hash unless blog.save

{ blog: blog }
end
end
end

Let’s understand what is generated:
description is used for graphql documentation to provide information about the mutation.

field is used to inform what to return if the blog is created successfully. argument is used to define the arguments to get from the mutation query, which is used to create a blog.

Finally, we have resolve method, which takes arguments, and here we write the logic to create the blog.

Now, we will use GraphiQL to execute our mutation. We would write as follows:

mutation createBlog{
blogCreate(input: {title: "test", description: "testing", userId: 16}){
blog{
id
title
}
}
}

We will provide all the arguments in input: and on successful creation, we would fetch id and title from the created blog. On executing a query, we would get the following response:

{
"data": {
"blogCreate": {
"blog": {
"id": "41",
"title": "test"
}
}
}
}

You can also check in the rails console to see if the blog is created or not using Blog.last .

Update Mutations

For writing update mutation, there’s mutation_update generator provided by graphql_gem:

rails g graphql:mutation_update blog

It will create a blog_update.rb file in the mutations folder.

Let’s modify it to:

# app/graphql/mutation/blog_update.rb
module Mutations
class BlogUpdate < BaseMutation
description "Updates a blog by id"

field :blog, Types::BlogType, null: false

argument :id, ID, required: true
argument :title, String, required: false
argument :description, String, required: false

def resolve(id:, title:, description:)
blog = ::Blog.find(id)
raise GraphQL::ExecutionError.new "Error updating blog", extensions: blog.errors.to_hash unless blog.update(title:, description:)

{ blog: blog }
end
end
end

Now, we will use GraphiQL to execute our mutation. We would write as follows:

mutation updateBlog{
blogUpdate(input: {id: 41, title: "How is it", description: "Hello world"}){
blog{
id
title
description
}
}
}

We are providing input for id to fetch the record to update and provide title and description to update the blog’s title and description. On successful blog update, we can fetch id ,title and description . Let’s execute the query:

{
"data": {
"blogUpdate": {
"blog": {
"id": "41",
"title": "How is it",
"description": "Hello world"
}
}
}
}

Delete Mutations

For writing delete mutation, there’s mutation_delete generator provided by graphql_gem:

rails g graphql:mutation_delete blog

It will create a blog_update.rb file in the mutations folder.

Let’s modify it to:

# app/graphql/mutation/blog_delete.rb
module Mutations
class BlogDelete < BaseMutation
description "Deletes a blog by ID"

field :message, String, null: false

argument :id, ID, required: true

def resolve(id:)
blog = ::Blog.find(id)
raise GraphQL::ExecutionError.new "Error deleting blog", extensions: blog.errors.to_hash unless blog.destroy!

{ message: 'Blog deleted successfully' }
end
end
end

Let’s open up GraphiQL to execute the delete blog mutation and write the following query:

mutation deleteBlog{
blogDelete(input: {id: 42}){
message
}
}

If the blog is deleted, we should get the following response:

{
"data": {
"blogDelete": {
"message": "Blog deleted successfully"
}
}
}

Thank you for reading.

In the next part, we will dive into authentication and authorization.

Keep following the Simform Engineering publication to know more about such insights and the latest trends in the development ecosystem.

Follow Us: Twitter | LinkedIn

--

--