Data Manipulation: A Dive into GraphQL Mutations in Rails 7 API
Empowering your Rails 7 API with GraphQL Mutations: Transforming data management with ease
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.