如何使用 Sangria 为在 GraphQL 中创建的实体提供 ID?
How can I give an ID to entities created in GraphQL using Sangria?
我有一个案例 class Inventory
:
case class Inventory(
organizationId: UUID,
inventoryId: UUID,
name: String,
schema: String
)
输入类型:
private val NewInventoryInputType =
deriveInputObjectType[Inventory](
InputObjectTypeName("NewInventory"),
ExcludeInputFields("organizationId", "inventoryId")
)
一个参数:
val NewInventory = Argument("inventory", NewInventoryInputType)
最后是一个字段:
val MutationType = ObjectType("Mutation", fields[GraphQLContext, Unit](
Field("createInventory", OptionType(UuidType),
Some("Creates a new inventory."),
NewInventory :: Nil,
resolve = c => {
val inventoryId = UUID.randomUUID
val inventory = c arg NewInventory
println(s"Inventory($inventory)")
inventoryId
}
)
))
我想做的是能够使用这样的查询创建一个 Inventory
:
{
"query": "mutation ($inventory: NewInventory!) { createInventory(inventory: $inventory) }",
"variables": {
"inventory": {
"name":"i1",
"schema":"s"
}
}
}
缺少的部分是在 Sangria 尝试使用其拥有的变量实例化 Inventory
域对象之前为 organizationId
和 inventoryId
创建 UUID 的位置。
目前,我收到此错误:
Argument 'inventory' has invalid value: At path '/inventoryId': error.path.missing (line 1, column 67):
mutation ($inventory: NewInventory!) { createInventory(inventory: $inventory) }
^
(当然,我可以只创建一个没有 ID 字段的 NewInventory
案例 class 并手动实例化一个 Inventory
,但我想避免创建和维护两个class每个实体类型都有。)
当您为案例 class 定义输入对象时,您需要定义两件事:
InputObjectType
- 它在 GraphQL 模式中声明了一个输入类型,并通过内省 API 公开了它的元信息。在您的示例中,您是在 deriveInputObjectType[Inventory]
宏的帮助下定义它的。
FromInput[Inventory]
type class 的隐式实例 - 它提供了有关如何从某些输入反序列化此输入对象的信息,例如 JSON。正如您在其他地方提到的,您已经用一些 JSON 库 (Json.format[Inventory]
) 定义了它
由于您从输入对象的定义中排除了 2 个字段,您还需要确保反序列化器知道它并且它应该能够处理缺少这 2 个字段的情况。在您的情况下 class,这两个字段是非可选的,这意味着 JSON 库(我假设您使用的是 play-json
)将始终期望这两个字段存在。这就是您看到此错误的原因:Argument 'inventory' has invalid value: At path '/inventoryId'
。错误实际上来自 play-json
因为在 GraphQL Schema 中你允许这个字段不存在但是 JSON 反序列化器不知道它
FromInput[Inventory]
type class 虽然提供了相当灵活的机制。我建议您查看它的文档,也许定义您自己的 implementation/wrapper 来处理这些缺失的字段。另一种方法是更多地朝着 CQRS 的方向发展,并定义 2 种不同的模式:一种用于查询,另一种用于突变输入(也可以在 scala 代码中表示为 2 个单独的案例classes)。当然,你也可以将两个可选字段都定义为Option[UUID]
.
我有一个案例 class Inventory
:
case class Inventory(
organizationId: UUID,
inventoryId: UUID,
name: String,
schema: String
)
输入类型:
private val NewInventoryInputType =
deriveInputObjectType[Inventory](
InputObjectTypeName("NewInventory"),
ExcludeInputFields("organizationId", "inventoryId")
)
一个参数:
val NewInventory = Argument("inventory", NewInventoryInputType)
最后是一个字段:
val MutationType = ObjectType("Mutation", fields[GraphQLContext, Unit](
Field("createInventory", OptionType(UuidType),
Some("Creates a new inventory."),
NewInventory :: Nil,
resolve = c => {
val inventoryId = UUID.randomUUID
val inventory = c arg NewInventory
println(s"Inventory($inventory)")
inventoryId
}
)
))
我想做的是能够使用这样的查询创建一个 Inventory
:
{
"query": "mutation ($inventory: NewInventory!) { createInventory(inventory: $inventory) }",
"variables": {
"inventory": {
"name":"i1",
"schema":"s"
}
}
}
缺少的部分是在 Sangria 尝试使用其拥有的变量实例化 Inventory
域对象之前为 organizationId
和 inventoryId
创建 UUID 的位置。
目前,我收到此错误:
Argument 'inventory' has invalid value: At path '/inventoryId': error.path.missing (line 1, column 67):
mutation ($inventory: NewInventory!) { createInventory(inventory: $inventory) }
^
(当然,我可以只创建一个没有 ID 字段的 NewInventory
案例 class 并手动实例化一个 Inventory
,但我想避免创建和维护两个class每个实体类型都有。)
当您为案例 class 定义输入对象时,您需要定义两件事:
InputObjectType
- 它在 GraphQL 模式中声明了一个输入类型,并通过内省 API 公开了它的元信息。在您的示例中,您是在deriveInputObjectType[Inventory]
宏的帮助下定义它的。FromInput[Inventory]
type class 的隐式实例 - 它提供了有关如何从某些输入反序列化此输入对象的信息,例如 JSON。正如您在其他地方提到的,您已经用一些 JSON 库 (Json.format[Inventory]
) 定义了它
由于您从输入对象的定义中排除了 2 个字段,您还需要确保反序列化器知道它并且它应该能够处理缺少这 2 个字段的情况。在您的情况下 class,这两个字段是非可选的,这意味着 JSON 库(我假设您使用的是 play-json
)将始终期望这两个字段存在。这就是您看到此错误的原因:Argument 'inventory' has invalid value: At path '/inventoryId'
。错误实际上来自 play-json
因为在 GraphQL Schema 中你允许这个字段不存在但是 JSON 反序列化器不知道它
FromInput[Inventory]
type class 虽然提供了相当灵活的机制。我建议您查看它的文档,也许定义您自己的 implementation/wrapper 来处理这些缺失的字段。另一种方法是更多地朝着 CQRS 的方向发展,并定义 2 种不同的模式:一种用于查询,另一种用于突变输入(也可以在 scala 代码中表示为 2 个单独的案例classes)。当然,你也可以将两个可选字段都定义为Option[UUID]
.