如何向 GraphQL 添加“resolveType”?

Posted

技术标签:

【中文标题】如何向 GraphQL 添加“resolveType”?【英文标题】:How to add a `resolveType` to GraphQL? 【发布时间】:2020-09-22 17:47:57 【问题描述】:

我正在尝试使用 GraphQL 查询单个 MongoDB 文档 (trivia),但其中一个文档字段出现问题。 trivia.rounds 字段应该返回一个对象数组(LightningRoundMultipleChoiceRound)。

schema.graphql

type Trivia 
  _id: String!
  createdAt: String!
  rounds: [Round]!


interface Round 
  type: String!
  theme: String!
  pointValue: Int!


type LightningRound implements Round 
  type: String!
  theme: String!
  pointValue: Int!
  questions: [LightningRoundQuestion]


type MultipleChoiceRound implements Round 
  type: String!
  theme: String!
  pointValue: Int!
  questions: [MultipleChoiceRoundQuestion]


// ...

trivia.js // resolver

require('dotenv').config()
const  ObjectId  = require('mongodb')

const trivia = (app) => 
  return async (root,  _id ) => 
    return app
      .get('db')
      .collection(process.env.DB_COLLECTION_TRIVIA)
      .findOne(ObjectId(_id))
  


module.exports = 
  trivia

graphql query

query 
  trivia(_id: "5e827a4e1c9d4400009fea32") 
    _id
    createdAt
    rounds 
      __typename
      ... on MultipleChoiceRound 
        type
        theme
        
            ... on PictureRound 
        type
        theme
        
            ... on LightningRound 
        type
        theme
        
    
  

我不断收到错误:

"message": "Abstract type \"Round\" must resolve to an Object type at runtime for field \"Trivia.rounds\" with value  questions: [[Object], [Object]] , received \"undefined\". Either the \"Round\" type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function."

我不明白resolveTypeisTypeOf 是什么意思。我在其他问题中看到了这一点,但不知道在我的设置中实现什么。如果我删除 rounds 字段,数据库连接和解析器工作正常,所以它就在那里......

【问题讨论】:

trivia 的解析器返回一个对象(来自 db),但它不包含 rounds 属性......并且没有解析器为此返回值(对象数组) @xadm 从trivia 返回的对象确实有rounds 数组,其中包含轮数。 @xadm 感谢您的提示。我来到这个全新的领域,试图围绕 GraphQL。我尝试了工会的东西,并没有奏效。我只是不知道该怎么做。哦,好吧。 【参考方案1】:

GraphQL 支持两种抽象类型——联合和接口。抽象类型是表示两个或多个可能类型的类型。抽象类型允许您为字段指定一种类型,该类型可能是运行时(即执行查询时)的几种可能类型之一。执行查询时,GraphQL 永远不能返回抽象类型——相反,当执行查询时,该类型必须解析为一种可能的类型。

如果一个字段返回一个列表,那么列表中每个项目的类型将单独解析。这种类型解析发生在每个项目上的任何字段被解析之前。更重要的是,解析的类型决定了首先需要解析哪些字段。

在上面的示例中,您定义了一个抽象类型(接口Round)和几种可能的类型(LightningRoundMultipleChoiceRound 等)。 但是,您还没有告诉 GraphQL 如何确定RoundLightningRoundMultipleChoiceRound 还是其他可能的类型。这就是提供resolveType 函数的目的。您通常为架构中的每个抽象类型定义一个 resolveType 函数。假设您使用的是graphql-toolsapollo-server,您可以通过用于定义解析器的同一个解析器映射对象来提供此功能:

const resolvers = 
  Round: 
    __resolveType: (round) => 
      // your code here
    ,
  ,

resolveType 将传递 Round 对象(即您的 rounds 解析器返回的对象之一)——您可以使用该值来确定它是哪种 Round。根据您的代码,我猜您会使用 type 属性来区分不同的类型。 resolveType 应该返回一个带有匹配类型名称的字符串值。所以它可以很简单:

const resolvers = 
  Round: 
    __resolveType: (round) => 
      return round.type
    ,
  ,

有关其他示例,请参阅the docs。

isTypeOf 是解析类型的另一种方法。您可以为每个可能的类型定义一个isTypeOf 函数,而不是为抽象类型定义一个resolveType 函数。此函数返回 true 或 false 以指示它接收到的对象是否实际上是该类型。 isTypeOf 有一些用途,但通常使用 resolveType 更容易。

【讨论】:

感谢您的深入回复!对此,我真的非常感激。唯一的事情,我不知道在哪里插入或执行解析器功能......我使用的是graphql-tools而不是阿波罗,如果有帮助的话。 如果您使用的是makeExecutableSchema,那么您将传递一个resolvers 选项给它。 resolvers 对象应如上所示(或在文档中)。 我正在使用addResolversToSchema,解析器会使其返回例如字符串“MultipleChoice”,实际上并没有任何数据。我迷路了。这太令人困惑了。 我会使用makeExecutableSchema,如graphql-tools 文档here 中所示。然后修改解析器对象以包含Round.__resolveType 函数,如我所示。

以上是关于如何向 GraphQL 添加“resolveType”?的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的 redux 操作向 GraphQL-server 发出请求?

如何使用 graphql 和护照设置身份验证但仍使用 Playground

向 graphql-ruby 实现添加多个过滤器

如何从猫鼬模型制作graphql?

关系 GraphQL

graphql 无法将 100 多种产品添加到我的 Wordpress Woocommerce 商店