如何使用 GraphQL 和 ApolloStack 解析联合/接口字段

Posted

技术标签:

【中文标题】如何使用 GraphQL 和 ApolloStack 解析联合/接口字段【英文标题】:How to resolve union/interface fields with GraphQL and 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() 等内容会更好。 【参考方案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 来完成。

以上是关于如何使用 GraphQL 和 ApolloStack 解析联合/接口字段的主要内容,如果未能解决你的问题,请参考以下文章

如何使用模拟的 graphql API 和外部服务的 GraphQL 端点

如何将 Mongoose 与 GraphQL 和 DataLoader 一起使用?

如何使用 Kickstart Spring Boot GraphQL 在逻辑上拆分我的 GraphQL 架构和解析器

如何使用 Rails 和 GraphQL 处理复杂的突变

如何使用 GraphQL 和 Mongodb 编写 lambda 函数?

如何使用 Graphql-kotlin 查询同时返回数据字段和错误字段