【问题标题】:How to resolve union/interface fields with GraphQL and ApolloStack如何使用 GraphQL 和 ApolloStack 解析联合/接口字段
【发布时间】:2017-05-28 14:19:57
【问题描述】:

我在我的 GraphQL 实例中使用接口,但这个问题可能也适用于联合。 实现接口的所有类型都有 2 个公共字段,但每种类型都有多个附加字段。

给定以下架构

interface FoodType {
  id: String
  type: String
}

type Pizza implements FoodType {
  id: String
  type: String
  pizzaType: String
  toppings: [String]
  size: String
}

type Salad implements FoodType {
  id: String
  type: String
  vegetarian: Boolean
  dressing: Boolean
}

type BasicFood implements FoodType {
  id: String
  type: String
}

以及以下解析器

{
  Query: {
    GetAllFood(root) {
      return fetchFromAllFoodsEndpoint()
        .then((items) => {
          return mergeExtraFieldsByType(items);
        });
    },
  },
  FoodType: {
    __resolveType(food) {
      switch (food.type) {
        case 'pizza': return 'Pizza';
        case 'salad': return 'Salad';
        default: return 'BasicFood';
      }
    },
  },
  Pizza: {
    toppings({pizzaType}) {
      return fetchFromPizzaEndpoint(pizzaType);
    }
  }
}

如何获取每种类型的附加字段?

目前,我有allFood获取所有食物以获取idtype的基本字段。在此之后,我将遍历结果,如果发现任何Pizza 类型,我将调用fetchFromPizzaEndpoint,获取附加字段并将它们合并到原始基本类型中。我对每种类型都重复此操作。

我还能够手动解析特定字段,一个类型,例如Pizza.toppings,如上所示。

现在我的解决方案并不理想,我更希望能够为每种类型解析多个字段,就像我对单个字段 toppings 所做的那样。 GraphQL 可以做到这一点吗?必须有更好的方法来实现这一点,因为这是一个很常见的用例。

理想情况下,我希望能够在我的解析器中知道我的查询需要哪些片段,因此我只能调用被请求的端点(每个片段一个端点)。

{
  Query: {
    GetAllFood(root) {
      return fetchFromAllFoodsEndpoint();
    },
  },
  FoodType: {
    __resolveType(food) {
      switch (food.type) {
        case 'pizza': return 'Pizza';
        case 'salad': return 'Salad';
        default: return 'BasicFood';
      }
    },
  },
  Pizza: {
    __resolveMissingFields(food) {
      return fetchFromPizzaEndpoint(food.id);
    }
  },
  Salad: {
    __resolveMissingFields(food) {
      return fetchFromSaladEndpoint(food.id);
    }
  }
}

【问题讨论】:

  • 能否详细说明每个dataLoader返回的内容是什么?这个用例对我来说看起来很陌生,尽管在我们的服务器实现中确实有几个联合类型的案例。对我们来说,我们从数据库中获取联合包含的任何数据(此时我们已经拥有所有数据而无需加载更多数据),然后决定 GraphQL 应该返回哪种类型的数据(在它的类型解析器)。
  • DataLoader 只是获取数据的 Facebook DataLoader,数据的来源并不重要。目前,我正在按照您提到的那样做,但是效率低下,因为我必须获取比我将要使用的更多的数据。例如,如果我只对“Pizza”进行分段,则不应将“Salad”属性下拉。拥有片段级解析器会很棒,但在与 GraphQL 开发人员交谈后,它似乎是一个未来的功能,目前不支持。
  • 这是我不明白的一点。如果您的数据实际上是披萨,您将如何获得沙拉属性?这就是为什么 DataLoader 返回哪些数据很重要的原因。例如,我们从 MongoDB 加载数据。如果您从 MongoDB 查询文档,它包含它所包含的内容(即,只有 Pizza 文档的“Pizza”数据)而没有其他内容。那里没有效率低下。如果您的意思是从 GraphQL 返回的数据效率低下,那么联合类型可以完美地为您处理。如果那是您担心的效率低下,我会写一个更详细的答案
  • 您可以直接调用数据库并按照您认为合适的方式构建查询(在本例中为 MongoDb),而在我的实例中,我正在与许多 REST Web 服务交谈。所以我打电话给 Query.GetAllFood - 这会影响服务以获得一切。但是,如果我执行“... on Pizza { toppings }”的片段,我想知道该片段并调用另一个 Web 服务端点来获取披萨数据并将其合并到我的结果中。目前我调用所有服务并合并所有不是一个很好的解决方案。
  • 您能否更新您的问题以包含该信息?我个人觉得没有它很难理解。当我有时间时,如果我有一个问题,我会写一个回答你的问题。事实上,如果你完全删除所有提及 dataLoader 并只使用 fetchFromPizzaEndpoint()fetchFromAllFoodsEndpoint() 等内容会更好。

标签: node.js graphql apollostack


【解决方案1】:

我知道这个问题已经 5 个月了,但我希望这可以帮助其他人解决这个问题。他正在传递他的解析器,其结构类似于

{
    Query: {
        GetAllFood(root) {
        return fetchFromAllFoodsEndpoint()
            .then((items) => {
            return mergeExtraFieldsByType(items);
            });
        },
    },
    FoodType: {
        __resolveType(food) {
        switch (food.type) {
            case 'pizza': return 'Pizza';
            case 'salad': return 'Salad';
            default: return 'BasicFood';
        }
        },
    },
    Pizza: {
        toppings({pizzaType}) {
        return fetchFromPizzaEndpoint(pizzaType);
        }
    }
}

但他确实想要类似的东西(不完全是,但我强调的是 __resolveType 相对于 Query 的位置)

{
    Query: {
        GetAllFood(root) {
        return fetchFromAllFoodsEndpoint()
            .then((items) => {
            return mergeExtraFieldsByType(items);
            });
        },
    },
    FoodType: {
        __resolveType(data, ctx, info) {
            return whatIsTheType(data, ctx, info)
        }
    }
}

官方文档有一个例子here,但它只包含接口类型,我觉得很困惑。我还有一个可用的联合类型(配置与接口相同)的完整可运行示例here

【讨论】:

  • 我实际上在几周前完全重写了它,完全按照你上面提到的那样做。差点忘了我在这里有这个问题:)
  • 那么问题出在哪里,您的回答是如何解决的?
  • 当您使用buildSchema 字符串构建架构时,有谁知道如何解决它?
  • 回答我的评论。添加了here 的功能,可以通过在您的对象上返回__typename 来完成。
猜你喜欢
  • 2017-04-02
  • 2020-05-27
  • 2019-06-12
  • 2020-08-31
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 2020-10-07
  • 2018-02-03
相关资源
最近更新 更多