首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GraphQL错误:未定义应为GraphQL类型

GraphQL错误:未定义应为GraphQL类型
EN

Stack Overflow用户
提问于 2020-02-18 08:29:06
回答 1查看 1.8K关注 0票数 0

在过去的一天左右的时间里,我一直遇到这个GraphQL错误,我很难找出问题所在。我希望下面的内容是有意义的。

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

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

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

代码语言:javascript
复制
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的解析器

代码语言:javascript
复制
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)。这就引出了问题类型:

代码语言:javascript
复制
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 (undefined),则只返回系统中的所有问题。这意味着在调查表类型中,在questions属性上,我们不想直接调用getQuestions解析器,但我们希望将它包装在一个解析器中,该解析器提取source.id (在此上下文中,source是调查表),并将其作为参数传递给getQuestions解析器。如果我们不这样做,那么在调查问卷上查询问题将始终返回系统中的所有问题,这是我们不想要的。

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

代码语言:javascript
复制
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解析器(因为这是我们在此上下文中始终需要的)。

然而,当我这样做的时候。我得到了这个错误:

代码语言:javascript
复制
[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行是:

代码语言:javascript
复制
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解析器中使用类似以下内容:

代码语言:javascript
复制
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
  },
}

但是,查看source来提取参数并不是getQuestions解析器的责任,而且,从技术上讲,source可能是调查问卷之外的另一个对象,从而增加了getQuestions解析器的复杂性。

感谢任何帮助和洞察力。

EN

回答 1

Stack Overflow用户

发布于 2020-02-18 09:43:53

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

一般情况下,应该避免在解析器中调用其他解析器。如果您有很多重复项,那么可以将共享逻辑提取到一个可以从两个解析器调用的公共函数中。当我们的解析器包含业务逻辑时,往往会发生这种情况--一种好的做法是尽量保持解析器的精简性,将业务逻辑隔离在单独的模型或服务中,然后可以从解析器调用这些模型或服务的方法。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60272156

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档