初学者了解GraphQL-第三部分
在《了解GraphQL for Beginners》的第二部分中,我们创建了可以获取数据的查询。在第三部分,我们学习什么是突变,并创建突变查询来修改数据。在我们开始之前,让我们回顾一下我们在这个系列中迄今为止所学到的东西:
- GraphQL是一种用于API的数据操作和查询语言
- 不再有过度和不足的数据取用
- 根字段根据选择的对象字段定义你的响应字段的结构。它们是GraphQL服务器的入口点(类似于端点)
- 对象字段是一个对象的属性
学习成果
- 创建一个GraphQL突变,以修改数据库中的数据。
- 使用GraphQL突变来创建一个新的ActiveRecord。
- 使用GraphQL突变修改数据。
- 使用GraphQL突变来销毁现有的ActiveRecord。
在你开始之前
在本教程中,我们将使用与第二部分相同的资源库。作为提醒,该资源库已经设置了GraphQL所需的模型和宝石。
下面的模型是
食物
| 属性 | 类型 |
| id | Bigint |
| 名称 | 字符串 |
| 原产地 | 符号 |
| 形象 | 形象 |
| 创建时间 | 时间戳 |
| 更新时间 | 时间戳 |
营养
| 属性 | 类型 |
| id | 大数 |
| food_id | 大数 |
| 服务量 | 绳子 |
| 卡路里 | 脂肪 |
| 总脂肪 | 脂肪 |
| 反式脂肪 | 饱和脂肪 |
| 饱和脂肪 | 字符串 |
| 胆固醇 | 字符串 |
| 钠 | 字符串 |
| 钾 | 字符串 |
| 总碳水化合物 | 字符串 |
| 膳食纤维 | 膳食纤维 |
| 糖类 | 膳食纤维 |
| 蛋白质 | 蛋白质 |
| 维生素_a | 字符串 |
| 维生素_c | 弦乐 |
| 钙质 | 字符串 |
| 铁 | 钙 |
| 创建时间 | 时间戳 |
| 更新时间 | 时间戳 |
什么是突变?
突变是在数据库中创建、修改或删除对象的查询,类似于REST中的PUT、POST或DELETE请求。突变请求被发送到与查询请求相同的端点。突变查询有以下结构:
mutation {
foodCreate(input: {
name: "Apple Pie",
placeOfOrigin: "US",
image: "apple-pie.png"
}) {
id
name
placeOfOrigin
image
}
}
- 查询以突变开始
- 任何需要的参数都在输入下
- 突变字段名包含它要执行的动作,即
foodCreate
我们在命名我们的突变查询时,先是一个对象,然后是动作。这对按字母顺序排列突变很有用,如下图所示:
| 先按对象排序 | 按动作先排序 |
| food_create.rb | create_food.rb |
| food_delete.rb | create_nutrition.rb |
| fiid_update.rb | delete_food.rb |
| 营养_创建.rb | delete_nutrition.rb |
| nutrition_delete.rb | update_food.rb |
| nutrition_update.rb | update_nutrition.rb |
左图:用一个对象先命名一个突变,然后再命名动作。右边。命名一个突变时,先是动作,然后是对象。
我们并不倾向于使用哪种命名方式,但是,我们使用图片左边的命名方式。你可以在mutations 目录下找到所有的突变,在types 目录下找到mutation_type.rb 。
创建你的第一个突变查询
我们创建一个foodCreate 突变来创建新的食物项目。要创建一个突变查询,在你的终端输入以下内容。rails g graphql:mutation foodCreate
rails generator ,做以下事情:
- 检查像
base_mutation.rb和mutation_type.rb这样的新突变文件是否存在。如果不存在,就创建它们。 - 添加根字段,
food_create到mutation_type.rb。 - 创建一个名为
food_create.rb的类。
让我们到mutation_type.rb类中,删除名为test_field 的字段和方法。
field :test_field, String, null: false,
description: "An example field added by the generator"
def test_field
"Hello World"
end
请注意,我们不需要在这里写一个方法,像在 query_type.rb.的突变。Mutations::foodCreate在该突变类中执行了一个名为resolve 的方法。我们很快就会知道resolve 这个方法是什么。然后我们进入food_create.rb,你的类看起来像这样。
module Mutations
class FoodCreate < BaseMutation
# TODO: define return fields
# field :post, Types::PostType, null: false
# TODO: define arguments
# argument :name, String, required: true
# TODO: define resolve method
# def resolve(name:)
# { post: ... }
# end
end
end
我们要做的第一件事是添加输入参数。删除所有的注释,然后添加以下内容。
module Mutations
class FoodCreate < BaseMutation
argument :name, String, required: true
argument :place_of_origin, String, required: true
argument :image, String, required: true
end
end
GraphQL默认使用camel大小写(placeOfOrigin)。为了与Shopify的风格指南保持一致,我们将使用蛇形大小写(place_of_origin)来代替。该字段的蛇形大小写会被GraphQL自动转换为驼峰大小写
接下来,我们需要添加一个解析方法。解析方法为其字段获取数据(food_create frommutation_type.rb )并返回一个响应。GraphQL服务器在其模式中每个字段只有一个解析方法。
module Mutations
class FoodCreate < BaseMutation
argument :name, String, required: true
argument :place_of_origin, String, required: true
argument :image, String, required: true
def resolve(**args)
end
end
end
你可能想知道** 是什么。这是一个叫做double splat的运算符,它向解析方法传递一个哈希值。这允许我们传递尽可能多的参数。为了获得最佳实践,如果有三个以上的参数,请使用双拼接来传递参数。为了简单起见,我们对三个参数使用双拼。
然后,我们添加类型Types::FoodCreate ,以表示我们的响应字段,并在解析方法中,创建一个新的ActiveRecord。
module Mutations
class FoodCreate < BaseMutation
argument :name, String, required: true
argument :place_of_origin, String, required: true
argument :image, String, required: true
type Types::FoodType
def resolve(**args)
Food.create!(args)
end
end
end
现在,让我们在GraphiQL上测试一下吧!转到http://localhost:3000/graphiql,测试我们新的突变查询!
编写以下查询。
mutation {
foodCreate(input: {
name: "Apple Pie",
placeOfOrigin: "US",
image: "apple-pie.png"
}) {
id
name
placeOfOrigin
image
}
}
当你执行该查询时,你会得到以下响应。
{
"data": {
"foodCreate": {
"id": "4",
"name": "Apple Pie",
"placeOfOrigin": "US",
"image": "apple-pie.png"
}
}
}
自己尝试一下 #1
创建一个名为nutritionCreate 的突变,创建一个新的Nutrition ActiveRecord。由于Nutrition类有很多属性,从这个gist中复制输入参数:https://gist.github.com/ShopifyEng/bc31c9fc0cc13b9d7be04368113b49d4
如果你想看解决方案,请查看nutrition_create.rb以及它的查询和响应。
创建突变以更新现有的食物项目
使用rails g graphql:mutation foodUpdate 创建一个名为foodUpdate的新突变。在food_update类里面,我们需要添加更新的参数。ID ,这将是参数的一部分。
module Mutations
class FoodUpdate < BaseMutation
argument :id, ID, required: true
argument :name, String, required: false
argument :place_of_origin, String, required: false
argument :image, String, required: false
end
end
这里唯一需要的参数是 ID.我们需要用一个 **ID**来寻找一个现有的产品。这使得resolve方法能够找到食品项目并更新它。
接下来,我们写出解析方法和响应回馈:
module Mutations
class FoodUpdate < BaseMutation
argument :id, ID, required: true
argument :name, String, required: false
argument :place_of_origin, String, required: false
argument :image, String, required: false
type Types::FoodType
def resolve(**args)
food = Food.find(args[:id])
food.update!(args)
return food
end
end
end
让我们测试一下这个新的突变查询。我们把我们的新食物项目从苹果派改名为南瓜派。
mutation {
foodUpdate(input: {
id: 4,
name: "Pumpkin Pie"
}) {
id
name
}
}
{
"data": {
"foodUpdate": {
"id": "4",
"name": "Pumpkin Pie"
}
}
}
自己尝试一下 #2
创建一个名为nutritionUpdate的突变,以更新一个现有的Nutrition ActiveRecord。
由于Nutrition类有很多属性,从这个gist中复制输入参数:https://gist.github.com/ShopifyEng/406065ab6c6ce68da6f3a2918ffbeaab。
如果你想看解决方案,请查看nutrition_update.rb和查询以及其查询和响应。
创建突变以删除现有的食物项目
使用rails g graphql:mutation foodDelete ,创建一个名为foodDelete的新突变。food_delete.rb 中唯一需要的参数是ID:
module Mutations
class FoodDelete < BaseMutation
argument :id, ID, required: true
end
end
接下来,我们需要添加返回类型和解析方法。为了简单起见,我们只使用Types::FoodType 作为响应:
module Mutations
class FoodDelete < BaseMutation
argument :id, ID, required: true
type Types::FoodType
def resolve(id:)
food = Food.find(id)
food.destroy!
return food
end
end
end
让我们在GraphiQL中测试这个突变:
mutation {
foodDelete(input: {
id: 4
}) {
id
}
}
{
"data": {
"foodDelete": {
"id": "4"
}
}
}
自己尝试 #3
创建一个名为nutritionDelete的突变,删除一个现有的Nutrition ActiveRecord。与foodDelete类似,我们使用Types::NutritionType 作为响应。
如果你想看看这个解决方案,请查看nutrition_delete.rb以及它的查询和响应。
我们已经到了本教程的结尾,我希望你喜欢创建突变来修改、创建或删除数据。
让我们回顾一下我们学到的东西
- 突变是在数据库中创建、修改或删除对象的查询。
- 为了生成一个突变,我们使用
rails g graphql:mutation nameAction。 - 一个解析方法为其字段(来自mutation_type.rb的food_create)获取数据,并返回一个响应。
- GraphQL服务器在其模式中每个字段只有一个解析方法。
GraphQL是一种强大的数据操作和查询语言,为API提供了很多灵活性。有时,在你的应用程序中实施GraphQL似乎非常令人生畏。我希望了解GraphQL的初学者系列能帮助你在个人项目中实施GraphQL,或说服你的工作采用GraphQL生态系统。
如果你想看第三部分的完成代码,请查看名为part-3-solution的分支。