如何在 GraphQL 中解析来自多个数据源的字段
Posted
技术标签:
【中文标题】如何在 GraphQL 中解析来自多个数据源的字段【英文标题】:howto resolve fields from multiple datasources in GraphQL 【发布时间】:2021-03-06 15:06:46 【问题描述】:关于设置 GraphQL 的初学者问题。我正在努力寻找最有效的方式为我的架构设置解析器。 在我的模式中说我有一个用户类型。某些字段在一个后端 api 中解析,其他字段在另一个中解析。
type User
name: String
address: String
dateOfBirth: String
department: String
function: String
manager: String
name、address 和 dateOfBirth 来自基本管理,其他字段来自组织数据库。 假设这是我的解析器:
Query
User(parent, args, ctx)
return
name: '....',
address: '...',
dateOfBirth: '.....'
以及特定子字段的解析器:
User
department(parent, args, ctx)
function(parent, args, ctx)
manager(parent, args, ctx)
如果用户请求所有字段,这将导致 4 个请求。最后三个请求可能是一次获取所有字段的 1 个请求。我当然希望这是 2 个请求:一个用于基本信息,一个用于组织 API。这可能会导致这种模式:
type User
name: String
address: String
dateOfBirth: String
organisation: Organisation
type Organisation
department: String
function: String
manager: String
和我的子字段解析器:
User
organisation
return
department: '...',
function: '...'
manager: '...'
现在对组织 API 的请求只被请求一次。但是,模式看起来很奇怪:这些字段应该是子对象的一部分。如果我们例如要将管理器数据移动到它自己的 API,如果我们将其移出子对象组织,架构将会中断。 我尝试使用数据加载器解决这个问题,但是在尝试了一些代码示例之后,我认为数据加载器更多的是关于 n+1 问题,围绕相同对象类型的键,而不是批处理不同的字段。 那么,解决这个问题的正确方法是什么?
【问题讨论】:
在 User 的解析器上,它必须返回一个 User 类型的对象,只需在此处进行两个 API 调用并组成对象被退回。然后这个 User 对象被传播到子解析器,它已经被解析了,所以你只需要从父解析器获取字段并返回它(一些规范默认这样做,所以你可以省略每个字段的解析器) @AlbertAlises - 问题是当不同的领域部门、职能部门和经理,你希望这些是一个 sep。 api 调用,仅在客户端请求时执行。这将建议将它们放在一个单独的子字段中,以便将它们分组,或者为所有字段单独设置解析器。在第一种情况下,您将根据解析字段的方式进行建模,我认为这不是好的做法。第二个选项是可取的,但比请求的每个字段都会导致单独的 api 调用。所以我需要一些请求字段的批处理,导致 1 api 调用。 【参考方案1】:在父解析器上解析(返回)的任何内容都会传播到子解析器。所以在 User 你可以这样做:
Query
User(parent, args, ctx)
//Call your API here that returns the organization fields
const organization = getOrganizationFields();
return
...organization
name: '....',
address: '...',
dateOfBirth: '.....'
然后在子解析器(字段解析器)上,该信息将可用,因此您可以这样做:
User
department(parent, args, ctx)
return parent.department
manager(parent, args, ctx)
return parent.manager
graphql-js
等一些实现使这些“单一”解析器隐含,因此您不必编写它们。当然,如果你想批量/缓存 API 请求,你应该使用DataLoader
【讨论】:
【参考方案2】:这可能会导致这种模式:
type User
name: String
address: String
dateOfBirth: String
organisation: Organisation
type Organisation
department: String
function: String
manager: String
和我的子字段解析器:
User
organisation
// fetch from organisation service using parent.id
return
department: '...',
function: '...'
manager: '...'
现在对组织 API 的请求只被请求一次。
您正朝着正确的方向前进,因为通常 graphql 只允许您请求所需的内容。
Albert 的 [用户级解析器] 一个数据源可能会发生过度获取(一个带有连接的 SQL 请求)。
但是,架构看起来很奇怪:这些字段应该是子对象的一部分。
可以,但不代表不能这样解决。
如果我们例如要将经理数据移动到它自己的 API, 如果我们将其移出子对象 Organisation,架构将会中断。
是的......也许你应该有更多的结构模式
...你可能是:
使用现有服务/BE 视角查看此架构; 将重大更改/API 版本控制问题混入此上下文中;...但是您已经可以定义“正确的架构”,f.e.
type User
name: String
address: String
dateOfBirth: String
role: Role
type Role
organisation: Organisation
function: String
type Organisation
department: String
manager: User
...假设每个用户只有一个角色...否则使用数组
在这种情况下,role
和 organisation
子对象可以通过一次调用组织服务来解决 - yust
return
function: "team lead",
organisation:
id: "someDeptID",
department: "some",
...如果您查询需要manager
字段,那么它将(应该)由Organisation.manager
解析器解析。当然,如果数据已经获取/可用,您可以将其返回(在 role
解析器中)。
【讨论】:
以上是关于如何在 GraphQL 中解析来自多个数据源的字段的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 GraphQL 和 ApolloStack 解析联合/接口字段
多个字段解析器使用不同的查询参数解析相同的 REST API
如何在 Apollo GraphQL Server 中添加字段解析器
如何使用 type-graphql 解析器函数获取 graphql 后端中的选定字段?