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

How do you handle lists that require joined data from multiple data sources in AppSync/GraphQL?

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

type Query {
    employees: [Employee]
}

这是一个虚构的模式来说明我的问题。我有两个单独的数据源,return 列出了需要加入以填充响应的数据源。第一个数据源 'employee list api' 是一个 http API 我可以查询以获得一个权威的员工列表,我可以用它来填充 idname 列。例如,我收到这样的回复:

[
    {"id": "001", "name": "Harry"},
    {"id": "002", "name": "Jerry"},
    {"id": "003", "name": "Larry"}
]

我有第二个 http API 'employee observation log' 我可以查询以获取状态列表以及关联的 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"}
]

现在,我希望 graphQL 响应 return 像这样:

{
  "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
      }
    ]
  }
}

由于 'employee list api' 是关于哪些员工存在的权威来源,因此对 'employee' 字段的所有查询都应始终触发对该 api 的查询,但 'employee observation log' api 只有在查询中选择了 'lastObservedStatus' 字段时才会触发。

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

我觉得处理这个问题的正确方法是将 lambda 解析器附加到 employees 字段,并在 lambda 解析器中检查查询的 selectionSetList 以检查 'lastObservedStatus' 字段是否已被选中。如果不是,则 lambda 仅查询 'employee list api',否则 lambda 还会查询 'employee observation log' 并在 return 结果之前执行类似于 SQL 连接的操作。但这是处理这个问题的正确方法吗?

听起来您需要的是 lastObservedStatus 字段上的解析器,它使用您的第二个 API ('employee observation log') 作为数据源,其中查询字段 employees 正在使用第一个 API 作为其数据源。

此解析器应使用 context source field('parent' 值,在本例中为 Employeeidname 进行查询可以参考)。例如,您可以使用 $ctx.source.id 在 VTL 代码中引用它,如果需要名称,则可以使用 $ctx.source.name

此解析器应该只查询 单身 员工的状态,因为它会在您的查询中的每个 every 结果中调用一次字段 employees.

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

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

实施起来会比较麻烦,但如果设计得当,将需要更少的 API 次调用。