In my last post we learned how to integrate GraphQL into Rails project and write first queries to retrieve data from backend.
Now let’s see how we can add, update and destroy entries.
We have new task_type.rb file:
#/app/graphql/types/task_type.rb
Types::TaskType = GraphQL::ObjectType.define do
name 'Task'
field :id, !types.ID
field :title, !types.String
field :description, !types.String
field :due_date, types.String
field :user, !types[Types::UserType] do
resolve -> (obj, args, ctx) {
obj.user
}
end
field :updated_at do
type types.Int
resolve -> (obj, args, ctx) {
obj.updated_at.to_i
}
end
field :created_at do
type types.Int
resolve -> (obj, args, ctx) {
obj.created_at.to_i
}
end
end
Let’s create mutation_type.rb file. And describe our new Mutations.
#/app/graphql/types/mutation_type.rb
Types::MutationType = GraphQL::ObjectType.define do
name 'Mutation'
field :addTask, field: Mutations::TaskMutations::Create.field
field :updateTask, field: Mutations::TaskMutations::Update.field
field :destroyTask, field: Mutations::TaskMutations::Destroy.field
end
And add new QueryType:
#/app/graphql/types/query_type.rb
Types::QueryType = GraphQL::ObjectType.define do
name "Query"
# ...
field :tasks, !types[Types::TaskType] do
argument :limit, types.Int, default_value: 10, prepare: -> (limit) { [limit, 30].min }
resolve -> (obj, args, ctx) {
Task.limit(args[:limit]).order(id: :desc)
}
end
field :task do
type Types::TaskType
argument :id, !types.ID
description "Find a Task by ID"
resolve ->(obj, args, ctx) { Task.find_by_id(args["id"]) }
end
end
Also, add Input object - for us, it’s a simple thing, which should describe input params for our queries.
#/app/graphql/input_objects/task_input_object_type.rb
TaskInputObjectType = GraphQL::InputObjectType.define do
name 'TaskInput'
input_field :title, !types.String
input_field :description, !types.String
input_field :user_id, types.Int
input_field :due_date, types.String
end
And finally our TaskMutations module, where we describe input fields, queries, input and return parameters.
#/app/graphql/mutations/task_mutations.rb
module Mutations::TaskMutations
Create = GraphQL::Relay::Mutation.define do
name 'AddTask'
input_field :task, !TaskInputObjectType
return_field :task, Types::TaskType
return_field :errors, types.String
resolve lambda { |object, inputs, ctx|
task = Task.new(inputs[:task].to_h)
if task.save
{ task: task }
else
{ errors: task.errors.to_a }
end
}
end
Update = GraphQL::Relay::Mutation.define do
name 'UpdateTask'
input_field :id, !types.ID
input_field :task, !TaskInputObjectType
return_field :task, Types::TaskType
return_field :errors, types.String
resolve lambda { |_object, inputs, _ctx|
task = Task.find_by_id(inputs[:id])
return { errors: 'Task not found' } if task.nil?
if task.update_attributes(inputs[:task].to_h)
{ task: task }
else
{ errors: task.errors.to_a }
end
}
end
Destroy = GraphQL::Relay::Mutation.define do
name 'DestroyTask'
description 'Delete a task and return deleted task ID'
input_field :id, !types.ID
return_field :deletedId, !types.ID
return_field :errors, types.String
resolve lambda { |_obj, inputs, _ctx|
task = Task.find_by_id(inputs[:id])
return { errors: 'Task not found' } if task.nil?
task.destroy
{ deletedId: inputs[:id] }
}
end
end
Let’s play with GraphQL console:
# add task
mutation addTask {
addTask(input: {
task: {
title: "GraphQL mutation",
user_id: 1,
description: "This article description"
}
}) {
task {
title
description
}
}
}
# update task
mutation updateTask {
updateTask(input: {
id: 14,
task: {
title: "GraphQL new mutation",
user_id: 1,
description: "This article description"
}
}) {
task {
title
description
}
}
}
# remove existing task:
mutation destroyTask {
destroyTask(input: {
id: 1,
}) {
deletedId
}
}