如何处理需要在 AppSync/GraphQL 中连接来自多个数据源的数据的列表?

Sea*_*ean 5 graphql aws-appsync aws-appsync-resolver

type Employee {
    id: String!
    name: String
    lastObservedStatus: String
}

type Query {
    employees: [Employee]
}
Run Code Online (Sandbox Code Playgroud)

这是一个虚构的模式来说明我的问题。我有两个单独的数据源,它们返回需要连接的列表才能填充响应。第一个数据源“员工列表 api”是一个 http API,我可以查询以获取权威的员工列表,我可以使用它来填充 和idname。例如,我收到这样的回复:

[
    {"id": "001", "name": "Harry"},
    {"id": "002", "name": "Jerry"},
    {"id": "003", "name": "Larry"}
]
Run Code Online (Sandbox Code Playgroud)

我有第二个 http API“员工观察日志”,我可以查询以获取状态列表以及关联的 ID。该 ID 允许我将号码与员工记录中的条目关联起来,并且我有一个记录日期。可能有不止一条状态记录,但在 GraphQL 中我只想选择最新的一条。响应示例:

[
    {"id":"002", "TimeStamp":"2021-07-01T12:30:00Z", "status": "eating"},
    {"id":"002", "TimeStamp":"2021-07-01T13:10:00Z", "status": "staring out the window"},
    {"id":"001", "TimeStamp":"2021-07-01T16:00:00Z", "status": "sleeping in lobby"}
]
Run Code Online (Sandbox Code Playgroud)

现在,我希望 graphQL 响应返回如下内容:

{
  "data": {
    "employees": [
      {
        "id": "001",
        "name": "Harry",
        "lastObservedStatus": "sleeping in lobby"
      },
      {
        "id": "002",
        "name": "Jerry",
        "lastObservedStatus": "staring out the window"
      },
      {
        "id": "003",
        "name": "Larry",
        "lastObservedStatus": null
      }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

由于“员工列表 api”是有关员工存在的权威来源,因此对“员工”字段的所有查询应始终触发对该 api 的查询,但“员工观察日志”api 仅应在“lastObservedStatus”字段存在时触发在查询中被选择。

对于这样的模式,解析器应该在哪里注册?我读过,最佳实践是始终在叶节点附加解析器,但我不确定在这种情况下如何做到这一点。我什至不确定如果您在列表的子字段上附加解析器会发生什么。

我觉得处理这个问题的正确方法是将 lambda 解析器附加到该employees字段,并在 lambda 解析器中检查查询的选择集列表以检查是否已选择“lastObservedStatus”字段。如果不是,则 lambda 只查询“员工列表 api”,否则 lambda 还会查询“员工观察日志”,并在返回结果之前执行类似于 SQL 连接的操作。但这是处理这个问题的正确方法吗?

Kev*_*ard 1

听起来您需要的是lastObservedStatus使用第二个 API(“员工观察日志”)作为数据源的字段解析器,其中查询字段employees使用第一个 API 作为其数据源。

该解析器应使用上下文源字段(在本例中为“父”值id以及您可以引用的name值)执行查询。Employee您可以在 VTL 代码中引用它,$ctx.source.id例如,或者$ctx.source.name如果您需要名称。

该解析器应该只查询单个Employee的状态,因为查询字段中的每个结果都会调用它一次employees

还有另一种选择,即有一个 2 函数管道解析器,其中每个函数都指向不同的数据源:

  • 步骤 1 解析除以下字段之外的所有字段lastObservedStatus
  • 第 2 步解析lastObservedStatus结果并将结果与$ctx.prev.result​​ .

这实施起来会比较混乱,但如果设计得当,需要的 API 调用会更少。