0

我有一个委托给内部 gRPC 服务的 Apollo GraphQL 服务。该服务有一个端点,它返回一条包含 a 的消息,oneof我将其映射到UnionGraphQL 中的 a 。

这很简单,但在实施解析器时会涉及相当程度的样板。假设我有以下 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一个是指示所包含值类型的字符串,另一个是为该类型命名的属性。因此,例如,如果我有一个MyUnionMessage包含 aUnionType2的对象,则该对象将如下所示:

{
  value: 'type2',
  type2: {...}
}

这对于实现来说很好,因为我可以对 in 中的值__resolveType做一个简单的处理,但是我必须为所有具体类型的所有字段编写一个解析器switchvalue

我正在寻找的是能够做到这样的事情:

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];
    },
  },
};

基本上,我想在通用联合(或接口)类型级别编写一个“解析器”,在对象传递给具体解析器之前对其进行转换。

这样的事情可能吗?

4

1 回答 1

0

我敢打赌,这种情况通常可以通过在数据到达__resolveType逻辑之前转换数据来解决。例如,假设您有一个Query返回列表的字段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
    }
  })
}

然后你switchtype里面,__resolveType你很高兴。当然,这意味着如果您有多个返回 a 的字段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,假设将来可能会发生变化。

于 2019-01-10T22:41:30.737 回答