在不同解析器上解析联合类型
Resolving Union Type on different Resolver
采取这个方案:
union Vehicle = Airplane | Car
type Airplane {
title: String
wingSpan: Int
}
type Car {
title: String
wheels: Int
}
type Person {
vehicle: [Vehicle!]
}
而这个查询:
person {
vehicles {
... on Car {
title
wheels
}
... on Airplane {
title
wingSpan
}
}
}
还有这些解析器:
// vehicle-resolver.js
export default {
Vehicle: {
__resolveType(obj) {
if (obj.wheels) {
return "Car"
} else {
return "Airplane"
}
}
}
}
// person-resolver.js
export default {
Person: {
vehicles(obj, args, context) {
// Am I resolving a car or an airplane now - or even both?
// I need to ask my CarService with `obj.personId` or my AirplaneService with `obj.personId` also, but I only want to query it if the query is asking for it.
}
}
}
在我的 Person -> vehicles(...)
上,我不确定何时应该查询我的不同服务以获得汽车和飞机?在方法中我不知道我们正在解析哪种类型。
您将无法知道您的 Union 在 内部 您的 vehicles
解析器中解析的类型,因为 Vehicle
上的 __resolveType
字段=] 实际上取决于它从解析器接收到的数据。
听起来您希望客户端能够请求服务器查询此人的汽车或 his/her 飞机,或两者,然后让服务器执行相应操作。这 通常 通过将参数传递给字段来完成,例如:
# type definitions
type Person {
vehicles(type: VehicleType): [Vehicle!]
}
enum VehicleType {
CAR
AIRPLANE
}
//resolver
vehicles(obj, { type }, context) {
if (type === 'CAR') // fetch and return cars
if (type === 'AIRPLANE') // fetch and return planes
// otherwise fetch and return both
}
从客户的角度来看,必须将类型标识为参数 (type: Car
) 然后在条件片段 (... on Car
) 中再次标识类型可能有点多余,但它是最简单的解决方案。
或者,您可以走记录较少的路径,查看客户端在每个请求的基础上实际请求了哪些字段。这可以通过深入研究 fourth argument passed to the resolver function(信息)来完成。我认为使用 Apollo,您应该能够像这样获取字段列表:
info.fieldNodes[0].selectionSet.selections.map(s => s.typeCondition.name.value)
然后您可以检查请求的是哪种类型,并让您的解析器采取相应的行动。
但是,使用前一种方法(即向字段添加类型参数)还有一个额外的好处。作为客户,如果我想将我的查询从获取汽车更改为获取飞机,我不想存储两个(或更多)不同的查询并且必须根据我尝试获取的类型在它们之间切换.
在客户端的上下文中,如果类型是可变的,它可能只是一个在应用程序状态中持久存在的变量。那么,作为客户,我宁愿随查询一起传递该变量。如果我的变量发生变化,我的查询结果也会发生变化,但我不必担心会更改查询本身(即它可以包含两种类型的条件片段)。
采取这个方案:
union Vehicle = Airplane | Car
type Airplane {
title: String
wingSpan: Int
}
type Car {
title: String
wheels: Int
}
type Person {
vehicle: [Vehicle!]
}
而这个查询:
person {
vehicles {
... on Car {
title
wheels
}
... on Airplane {
title
wingSpan
}
}
}
还有这些解析器:
// vehicle-resolver.js
export default {
Vehicle: {
__resolveType(obj) {
if (obj.wheels) {
return "Car"
} else {
return "Airplane"
}
}
}
}
// person-resolver.js
export default {
Person: {
vehicles(obj, args, context) {
// Am I resolving a car or an airplane now - or even both?
// I need to ask my CarService with `obj.personId` or my AirplaneService with `obj.personId` also, but I only want to query it if the query is asking for it.
}
}
}
在我的 Person -> vehicles(...)
上,我不确定何时应该查询我的不同服务以获得汽车和飞机?在方法中我不知道我们正在解析哪种类型。
您将无法知道您的 Union 在 内部 您的 vehicles
解析器中解析的类型,因为 Vehicle
上的 __resolveType
字段=] 实际上取决于它从解析器接收到的数据。
听起来您希望客户端能够请求服务器查询此人的汽车或 his/her 飞机,或两者,然后让服务器执行相应操作。这 通常 通过将参数传递给字段来完成,例如:
# type definitions
type Person {
vehicles(type: VehicleType): [Vehicle!]
}
enum VehicleType {
CAR
AIRPLANE
}
//resolver
vehicles(obj, { type }, context) {
if (type === 'CAR') // fetch and return cars
if (type === 'AIRPLANE') // fetch and return planes
// otherwise fetch and return both
}
从客户的角度来看,必须将类型标识为参数 (type: Car
) 然后在条件片段 (... on Car
) 中再次标识类型可能有点多余,但它是最简单的解决方案。
或者,您可以走记录较少的路径,查看客户端在每个请求的基础上实际请求了哪些字段。这可以通过深入研究 fourth argument passed to the resolver function(信息)来完成。我认为使用 Apollo,您应该能够像这样获取字段列表:
info.fieldNodes[0].selectionSet.selections.map(s => s.typeCondition.name.value)
然后您可以检查请求的是哪种类型,并让您的解析器采取相应的行动。
但是,使用前一种方法(即向字段添加类型参数)还有一个额外的好处。作为客户,如果我想将我的查询从获取汽车更改为获取飞机,我不想存储两个(或更多)不同的查询并且必须根据我尝试获取的类型在它们之间切换.
在客户端的上下文中,如果类型是可变的,它可能只是一个在应用程序状态中持久存在的变量。那么,作为客户,我宁愿随查询一起传递该变量。如果我的变量发生变化,我的查询结果也会发生变化,但我不必担心会更改查询本身(即它可以包含两种类型的条件片段)。