如何使用 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 域对象之前为 organizationIdinventoryId 创建 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 定义输入对象时,您需要定义两件事:

  1. InputObjectType - 它在 GraphQL 模式中声明了一个输入类型,并通过内省 API 公开了它的元信息。在您的示例中,您是在 deriveInputObjectType[Inventory] 宏的帮助下定义它的。
  2. FromInput[Inventory] type class 的隐式实例 - 它提供了有关如何从某些输入反序列化此输入对象的信息,例如 JSON。正如您在其他地方提到的,您已经用一些 JSON 库 (Json.format[Inventory])
  3. 定义了它

由于您从输入对象的定义中排除了 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].