【问题标题】:How can I give an ID to entities created in GraphQL using Sangria?如何为使用 Sangria 在 GraphQL 中创建的实体提供 ID?
【发布时间】:2018-03-15 03:08:25
【问题描述】:

我有一个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 案例类并手动实例化一个 Inventory,但我想避免为每个实体类型创建和维护两个类。)

【问题讨论】:

  • 在我的 Sangria 代码库中,我不使用任何 deriveInputObjectType,因为我不喜欢在我的 Sangria 类型和域模型之间进行一对一的耦合。我有一些情况,一个突变可能会创建 3,4 或 5 个域模型,其中一些被放入数据库等。另一个原因正是这种情况,你有一个 ID 字段而不是另一个。
  • @Tyler 你会做什么呢?将字段作为单独的参数传递?
  • 是的,我的每个突变都有单独的参数,而不仅仅是“对象”的一个参数

标签: scala graphql sangria


【解决方案1】:

当您为案例类定义输入对象时,您需要定义两件事:

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

由于您从输入对象的定义中排除了 2 个字段,因此您还需要确保反序列化器知道它,并且它应该能够处理缺少这 2 个字段的情况。在您的案例类中,这两个字段是非可选的,这意味着 JSON 库(我假设您使用的是 play-json)将始终期望这两个字段存在。这就是您看到此错误的原因:Argument 'inventory' has invalid value: At path '/inventoryId'。该错误实际上来自play-json,因为在 GraphQL Schema 中您允许该字段不存在但 JSON 反序列化器不知道它

FromInput[Inventory] type class 提供了相当灵活的机制。我建议您检查它的文档,并可能定义您自己的实现/包装器来处理这些缺失的字段。另一种方法是更多地朝着CQRS 的方向发展,并定义2 种单独的模式:一种用于查询,另一种用于突变输入(也可以在scala 代码中表示为2 个单独的案例类)。当然,您也可以将两个可选字段都定义为Option[UUID]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-07
    • 2016-08-21
    • 2019-02-06
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多