如何向 GraphQL 添加“resolveType”?

Sam*_*rko 1 mongodb node.js express graphql

我正在尝试trivia使用 GraphQL查询单个 MongoDB 文档 ( ),但在使用其中一个文档字段时遇到问题。这是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]
}

// ...
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

graphql query

query {
  trivia(_id: "5e827a4e1c9d4400009fea32") {
    _id
    createdAt
    rounds {
      __typename
      ... on MultipleChoiceRound {
        type
        theme
        }
            ... on PictureRound {
        type
        theme
        }
            ... on LightningRound {
        type
        theme
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我不断收到错误:

"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."
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*den 6

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

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

在你上面的例子,你定义了一个抽象类型(接口Round为它)和几个可能的类型(LightningRoundMultipleChoiceRound,等)。但是,您还没有告诉 GraphQL 如何确定 aRound是 a LightningRound、aMultipleChoiceRound还是其他可能的类型。这是提供resolveType函数的目的。您通常resolveType为架构中的每个抽象类型定义一个函数。假设您正在使用graphql-toolsor apollo-server,您通过用于定义解析器的相同解析器映射对象提供此功能:

const resolvers = {
  Round: {
    __resolveType: (round) => {
      // your code here
    },
  },
}
Run Code Online (Sandbox Code Playgroud)

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

const resolvers = {
  Round: {
    __resolveType: (round) => {
      return round.type
    },
  },
}
Run Code Online (Sandbox Code Playgroud)

有关其他示例,请参阅文档

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