javascript - GraphQL错误: Expected undefined to be a GraphQL type

标签 javascript graphql apollo-server

在过去一天左右的时间里,我一直遇到这个 GraphQL 错误,而且我很难确定问题出在哪里。我希望以下内容有意义......

在我的项目中,我有以下 GraphQL 类型;调查问卷和问题是一个调查问卷有很多问题,一个问题属于一个调查问卷。

我有以下查询:getQuestionnaires(获取所有调查问卷)、getQuestionnaire(通过 ID 获取单个调查问卷)、getQuestions(获取所有问题,可以是系统中的所有问题,也可以是通过指定 questionnaireId 获取调查问卷的问题。

这是问卷类型(为了简洁起见,我省略了一些属性):

import {
  GraphQLID,
  GraphQLObjectType,
  GraphQLNonNull,
} from 'graphql'
import QuestionType from './Question'
import QuestionResolver from '../resolver/question'

const QuestionnaireType: GraphQLObjectType = new GraphQLObjectType({
  name: 'Questionnaire',
  fields() {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLID),
      },

      // other literal attributes go here

      questions: QuestionResolver.query.getQuestions,
    }
  },
})

export default QuestionnaireType

如您所见,问卷类型的 questions 属性只是调用 getQuestions 的解析器。

这是 getQuestions 的解析器:

import {
  GraphQLList,
  GraphQLID
} from 'graphql'

import QuestionType from '../../type/Question'

export default {
  type: GraphQLList(QuestionType),
  description: 'Returns a list of questions',
  args: {
    questionnaireId: {
      type: GraphQLID,
      description: 'Questions that belong to this questionnaire',
    },
  },
  async resolve(source: any, { questionnaireId = undefined }: any, ctx: any): Promise<any> {
    // Based on the `questionnaireId` get the questions. If `undefined` get "all" questions.
  },
}

如您所见,getQuestions 返回一个 GraphQLList(QuestionType)。这给我们带来了问题类型:

import {
  GraphQLID,
  GraphQLObjectType,
  GraphQLNonNull,
} from 'graphql'
import QuestionnaireType from './Questionnaire'
import QuestionnaireResolver from '../resolver/questionnaire'

const QuestionType: GraphQLObjectType = new GraphQLObjectType({
  name: 'Question',
  fields() {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLID),
      },

      questionnaire: QuestionnaireResolver.query.getQuestionnaire,
    }
  },
})

export default QuestionType

好的。到目前为止,一切都很好。此代码编译并运行。

但是,这段代码有一个问题。 getQuestions 解析器将调查问卷 ID 作为参数 (questionnaireId)。如果未传递调查问卷 ID(未定义),它只会返回系统中的所有问题。这意味着在问卷类型中,在 questions 属性上,我们不想直接调用 getQuestions 解析器,但我们希望将其包装在一个解析器中,以提取source.id(source 是本上下文中的调查问卷)并将其作为参数传递给 getQuestions 解析器。如果我们不这样做,那么在调查问卷上查询问题将始终返回系统中的所有问题,这是我们不想要的。

因此,我们将解析器包装在一个解析器中,该解析器在调用 getQuestions 解析器之前提取问卷 ID。我们的调查问卷类型现在如下所示:

import {
  GraphQLID,
  GraphQLObjectType,
  GraphQLNonNull,
} from 'graphql'
import QuestionType from './Question'
import QuestionResolver from '../resolver/question'

const QuestionnaireType: GraphQLObjectType = new GraphQLObjectType({
  name: 'Questionnaire',
  fields() {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLID),
      },

      // other literal attributes go here

      questions: {
        type: GraphQLList(QuestionType),
        async resolve(source: any, args: any, ctx: any): Promise<any> {
          return QuestionResolver.query.getQuestions.resolve(
            source,
            {
              questionnaireId: source.questionnaireId,
            },
            ctx
          )
        },
      },
    }
  },
})

export default QuestionnaireType

我们现在已经封装了 getQuestions 解析器来提取 source.id(即问卷 ID),以便我们始终可以将其传递给 getQuestions 解析器(因为这是我们在这种情况下总是想要的)。

但是,当我执行上述操作时。我收到此错误:

[Node] /Project/api/node_modules/graphql/type/definition.js:91
[Node]     throw new Error("Expected ".concat((0, _inspect.default)(type), " to be a GraphQL type."));
[Node]     ^
[Node]
[Node] Error: Expected undefined to be a GraphQL type.
[Node]     at assertType (/Project/api/node_modules/graphql/type/definition.js:91:11)
[Node]     at new GraphQLList (/Project/api/node_modules/graphql/type/definition.js:307:19)
[Node]     at Object.GraphQLList (/Project/api/node_modules/graphql/type/definition.js:309:12)
[Node]     at Object.<anonymous> (/Project/api/build/graphql/resolver/question/getQuestions.js:11:21)
[Node]     at Module._compile (internal/modules/cjs/loader.js:936:30)
[Node]     at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
[Node]     at Module.load (internal/modules/cjs/loader.js:790:32)
[Node]     at Function.Module._load (internal/modules/cjs/loader.js:703:12)
[Node]     at Module.require (internal/modules/cjs/loader.js:830:19)
[Node]     at require (internal/modules/cjs/helpers.js:68:18)

我被难住了......

getQuestions 第 11 行是:

08: export default {
09:   type: GraphQLList(QuestionType),
10:   description: 'Returns a list of questions',
11:   args: {
12:     questionnaireId: {
13:       type: GraphQLID,
14:       description: 'Questions that belong to this questionnaire',
15:     },

我想我已经尝试了所有能想到的方法来找到问题所在。我的项目很大,我在其他几个地方使用这种技术没有问题,但由于某种原因,在这个特定的场景中它无法编译..

我目前唯一的解决方法是在 getQuestions 解析器中使用类似的方法:

import {
  GraphQLList,
  GraphQLID
} from 'graphql'

import QuestionType from '../../type/Question'

export default {
  type: GraphQLList(QuestionType),
  description: 'Returns a list of questions',
  args: {
    questionnaireId: {
      type: GraphQLID,
      description: 'Questions that belong to this questionnaire',
    },
  },
  async resolve(source: any, { questionnaireId = undefined }: any, ctx: any): Promise<any> {

    // The workaround
    const id = questionnaireId || source.id
  },
}

但是,getQuestions 解析器没有责任查看source 来提取参数,而且 source 在技术上可以是问卷之外的另一个对象,为 getQuestions 解析器增加了更多复杂性。

感谢任何帮助和见解。

最佳答案

您需要查看编译后的代码来跟踪错误。不过,根据堆栈跟踪,QuestionType 的计算结果似乎是 undefined。当您存在循环依赖关系时(即模块 A 导入模块 B,模块 B 导入模块 A 等),就会发生这种情况。

您通常应该避免在解析器内部调用其他解析器。如果有大量重复,可以将共享逻辑提取到一个可以从两个解析器调用的通用函数中。当我们的解析器包含业务逻辑时,很可能会发生这种情况 - 尝试使解析器尽可能精简,将业务逻辑隔离在单独的模型或服务中,然后可以从解析器调用其方法,这是一个很好的做法。

如果不查看所有相关代码,就很难知道如何修复循环依赖。解决任何循环依赖关系的有保证的方法是将 import 语句替换为 fields 函数内的动态 require。但是,您可能不会发现该解决方案特别优雅。一个好的第一步可能是整合一些模块 - 例如,创建一个包含问题类型以及所有相关查询和突变字段的问题模块。

关于javascript - GraphQL错误: Expected undefined to be a GraphQL type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60272156/

相关文章:

javascript - 如何使用 XMLHttpRequest 和 asp.net MVC 将大型 blob 发布到服务器?

javascript - Mocha 作为图书馆

javascript - Prestashop 1.6 addJS 和 Css 在管理员的函数模块 getContent() 中不起作用

node.js - GraphQL 中继返回一条记录

javascript - 具有网关服务器作为服务的 Apollo 联邦

javascript - 打字时的千位分隔符和小数点(带逗号)

node.js - 我这个 GraphQL 查询做错了什么?

swift - 如何编写 GraphQL 查询

react-hooks - 测试 useSubscription apollo hooks with react

node.js - 如何将 Apollo 服务器错误发送给 Sentry?