采用这种方案:
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(...)
我不确定何时应该查询我的不同服务以获取汽车和飞机?在方法中,我不知道我们正在解决哪种类型。
答案 0 :(得分:1)
由于vehicles
上__resolveType
字段实际依赖于Vehicle
,因此您无法知道您的联盟将哪种类型解析为内部您的[{1}}解析器它从解析器接收的数据。
听起来您希望客户端能够请求服务器查询Person的汽车或他/她的飞机,或两者,然后让服务器采取相应的行动。通常通过将参数传递给字段来完成 ,例如:
# 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)
然后,您可以检查请求的类型,并让您的解析器采取相应的行动。
然而,以前一种方式(通过向字段添加类型参数)有一个额外的好处。作为一个客户端,如果我想将我的查询从获取汽车更改为获取飞机,我不希望存储两个(或更多)不同的查询,并且必须根据我试图获取的类型在它们之间切换
在客户端的上下文中,如果类型是可更改的,那么它可能只是在应用程序状态中持久存储的变量。作为客户端,我更愿意将该变量与我的查询一起传递。如果我的变量发生变化,我的查询结果会发生变化,但我不必担心改变查询本身(即它可以包含两种类型的条件片段)。