覆盖 "root" GraphQL Union/Interface 类型的对象值
Overriding "root" object value of GraphQL Union/Interface type
我有一个委托给内部 gRPC 服务的 Apollo GraphQL 服务。此服务有一个端点,其中 returns 包含 oneof
的消息,我将其映射到 GraphQL 中的 Union
。
这很简单,但是在实施解析器时涉及相当程度的样板文件。假设我有以下 protobuf 消息定义:
message MyUnionMessage {
oneof value {
UnionType1 type1 = 1;
UnionType1 type2 = 3;
UnionType1 type3 = 4;
}
}
message UnionType1 {<type 1 props>}
message UnionType2 {<type 2 props>}
message UnionType3 {<type 3 props>}
我对应的 GraphQL 架构如下所示:
union MyUnionType = UnionType1 | UnionType2 | UnionType3
type UnionType1 {<type 1 props>}
type UnionType1 {<type 2 props>}
type UnionType1 {<type 3 props>}
在 gRPC 的 javascript 绑定中,一个 MyUnionMessage
对象将有两个属性:value
是一个指示包含哪种类型的值的字符串,以及 属性 以类型命名。因此,例如,如果我有一个包含 UnionType2
的 MyUnionMessage
,该对象将如下所示:
{
value: 'type2',
type2: {...}
}
这很适合实现 __resolveType
,因为我可以对 value
中的值做一个简单的 switch
,但我必须为 编写一个解析器]all 所有具体类型的字段。
我正在寻找的是能够做到这样的事情:
resolvers = {
MyUnionType: {
__resolveType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: return null;
},
__resolveValue(obj) {
return obj[obj.value];
},
},
};
基本上,我想在通用联合(或接口)类型级别编写一个 "resolver",在将对象传递给具体解析器之前对其进行转换。
这样的事情可能吗?
我敢打赌,这种情况通常可以通过在数据达到 __resolveType
逻辑之前转换数据来解决。例如,假设您有一个 Query
字段 return 编辑了 MyUnionType
的列表。该字段的解析器可能类似于:
function resolve (arr) {
return arr.map(obj => {
return {
...obj[obj.value]
type: obj.value // or whatever field name that won't cause a collision
}
})
}
然后在 __resolveType
内 type
上 switch
就可以了。当然,这意味着如果您有多个 return 和 MyUnionType
的字段,您需要将该逻辑提取到每个解析器都可以使用的效用函数中。
我认为没有真正的方法可以用现有的 API 来完成您想要做的事情。当然,您可以这样做:
const getUnionType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: {
throw new Error(`Unrecognized type ${obj.value}`)
}
}
}
const resolvers = {
MyUnionType: {
__resolveType(obj) {
const type = getUnionType(obj)
Object.assign(obj, obj[obj.value])
return type
},
},
};
这行得通,但请记住它有点脆弱,因为它假设 resolveType
将始终获得与 resolve
函数相同的根值,假设将来可能会发生变化。
我有一个委托给内部 gRPC 服务的 Apollo GraphQL 服务。此服务有一个端点,其中 returns 包含 oneof
的消息,我将其映射到 GraphQL 中的 Union
。
这很简单,但是在实施解析器时涉及相当程度的样板文件。假设我有以下 protobuf 消息定义:
message MyUnionMessage {
oneof value {
UnionType1 type1 = 1;
UnionType1 type2 = 3;
UnionType1 type3 = 4;
}
}
message UnionType1 {<type 1 props>}
message UnionType2 {<type 2 props>}
message UnionType3 {<type 3 props>}
我对应的 GraphQL 架构如下所示:
union MyUnionType = UnionType1 | UnionType2 | UnionType3
type UnionType1 {<type 1 props>}
type UnionType1 {<type 2 props>}
type UnionType1 {<type 3 props>}
在 gRPC 的 javascript 绑定中,一个 MyUnionMessage
对象将有两个属性:value
是一个指示包含哪种类型的值的字符串,以及 属性 以类型命名。因此,例如,如果我有一个包含 UnionType2
的 MyUnionMessage
,该对象将如下所示:
{
value: 'type2',
type2: {...}
}
这很适合实现 __resolveType
,因为我可以对 value
中的值做一个简单的 switch
,但我必须为 编写一个解析器]all 所有具体类型的字段。
我正在寻找的是能够做到这样的事情:
resolvers = {
MyUnionType: {
__resolveType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: return null;
},
__resolveValue(obj) {
return obj[obj.value];
},
},
};
基本上,我想在通用联合(或接口)类型级别编写一个 "resolver",在将对象传递给具体解析器之前对其进行转换。
这样的事情可能吗?
我敢打赌,这种情况通常可以通过在数据达到 __resolveType
逻辑之前转换数据来解决。例如,假设您有一个 Query
字段 return 编辑了 MyUnionType
的列表。该字段的解析器可能类似于:
function resolve (arr) {
return arr.map(obj => {
return {
...obj[obj.value]
type: obj.value // or whatever field name that won't cause a collision
}
})
}
然后在 __resolveType
内 type
上 switch
就可以了。当然,这意味着如果您有多个 return 和 MyUnionType
的字段,您需要将该逻辑提取到每个解析器都可以使用的效用函数中。
我认为没有真正的方法可以用现有的 API 来完成您想要做的事情。当然,您可以这样做:
const getUnionType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: {
throw new Error(`Unrecognized type ${obj.value}`)
}
}
}
const resolvers = {
MyUnionType: {
__resolveType(obj) {
const type = getUnionType(obj)
Object.assign(obj, obj[obj.value])
return type
},
},
};
这行得通,但请记住它有点脆弱,因为它假设 resolveType
将始终获得与 resolve
函数相同的根值,假设将来可能会发生变化。