如何在GraphQL中解析来自多个数据源的字段



关于设置GraphQL的初学者问题。我正在努力寻找为我的模式设置解析器的正确方法,这是最有效的方法。假设在我的模式中我有一个User类型。一些字段在一个后端api中解析,另一些字段在另一个后台api中解析。

type User {
name: String
address: String
dateOfBirth: String
department: String
function: String
manager: String
}

姓名、地址和出生日期来自基本管理部门,其他字段来自组织数据库。假设这是我的解析器:

Query {
User(parent, args, ctx) {
return {
name: '....',
address: '...',
dateOfBirth: '.....'
}
}
} 

以及特定子字段的解析器:

User {
department(parent, args, ctx) {
}
function(parent, args, ctx) {
}
manager(parent, args, ctx) {
}
}

如果用户请求了所有字段,这将导致4个请求。最后三个请求可能是一个一次性获取所有字段的请求。我当然希望这是两个请求:一个是基本信息,一个是组织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,那么如果我们将其移出子对象Organisation,则模式将崩溃。我试着用数据加载器来解决这个问题,但在尝试了一些代码示例后,我认为数据加载器更多的是关于n+1问题,围绕相同对象类型的键,而不是批处理不同的字段。那么,解决这个问题的正确方法是什么呢?

在父解析程序上解析(返回(的内容都会传播到子解析程序。因此,在用户中,您可以执行以下操作:

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
}
}

诸如CCD_ 1之类的一些实现使得这些";酉";解析器是隐式的,所以您不必编写它们。当然,如果您想批量/缓存API请求,您应该使用DataLoader

这可能会导致以下模式:

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版本控制问题混合到该上下文中

。。。但你已经可以定义"正确的模式",例如

type User {
name: String
address: String
dateOfBirth: String
role: Role
} 
type Role {
organisation: Organisation
function: String
}
type Organisation {
department: String
manager: User

}

假设每个用户只有一个角色。。。否则使用数组

在这种情况下,roleorganisation子对象可以从一个对组织服务的调用中解析出来——yust

return {
function: "team lead",
organisation: {
id: "someDeptID",
department: "some",
}
}

如果您的查询将需要manager字段,那么它将(应该(由Organisation.manager解析器解析。当然,如果数据已经获取/可用,您可以将其返回到那里(在role解析器中(。

最新更新