【问题标题】:Node - GraphQL - Ad.user field type must be Output Type but got: undefined节点 - GraphQL - Ad.user 字段类型必须是输出类型,但得到:未定义
【发布时间】:2018-06-25 11:32:39
【问题描述】:

我似乎在 AdType 中使用 UserType 时遇到了循环依赖问题。

这是我的用户类型文件:UserType

这是我的 AdType 文件:AdType

如果我尝试使用下面的代码,即使我正确导入了 UserType,我也会收到错误“Ad.user field type must be Output Type but got: undefined”。

import { UserType } from '../User/user.graphql.model'
import { UserSchema } from '../User/user.mongoose.model'

const user =  {
  type: UserType,
  resolve(parentValue, args) {
    return UserSchema.findById(parentValue.user);
  }
};

//------------------------------
// Ad Type
//------------------------------
export const AdType = new GraphQLObjectType({
  name: 'Ad',
  fields: () => ({
    id,
    user,
    title,
    views,
    availability,
... more code

如果我在导入后尝试在 AdType 中对 UserType 进行控制台日志记录,它会显示未定义,但是当我将其用作:

//------------------------------
// Ad Type
//------------------------------
export const AdType = new GraphQLObjectType({
  name: 'Ad',
  fields: () => ({
    id,
    user: {
      type: UserType,
      resolve(parentValue, args) {
        return UserSchema.findById(parentValue.user);
      }
    },
    title,
... more code

它按预期工作,它只是不允许我提取代码来分隔常量。 我以相同方式导入和使用的所有其他类型都按预期工作,将广告导入用户也可以,但将用户导入广告似乎会中断。两者的代码基本相同,只是信息不同。

【问题讨论】:

  • 我已经在使用 fields: () => ( { } ) 来延迟加载字段以避免循环依赖的问题,所以这个问题真的很头疼。

标签: node.js output undefined graphql circular-dependency


【解决方案1】:

我已经在使用 fields: () => ( { } ) 来延迟加载字段以避免循环依赖的问题,所以这个问题真的很头疼。

但是您没有正确执行此操作。 Javascript 没有惰性求值。这意味着user 的值不是在调用函数时确定的,而是在评估const 变量定义的时间点确定的。此时变量UserType 没有值,因此未定义。您的对象定义需要在调用函数时进行。如果仍然不清楚,我可以提供详细说明您的类型是如何解决的。

尝试内联定义用户类型或使其成为函数:

const user = () => ({ type: UserType, /* ... */ })

export const AdType = new GraphQLObjectType({
  name: 'Ad',
  fields: () => ({
    id,
    user: user(),
    title,
    views,
    availability,

我不知道你为什么要把你的字段放到单独的常量中,你的代码看起来并没有那么大,它提高了可读性,但我当然可能是错的。

好的,让我们看看模块是如何解析的。为了使这更容易,我使用了 CJS,因为无论如何你很可能将代码转换下来,而 ES 模块只是慢慢地进入节点。

// user.graphql.model.js
const adModule = require('ad.graphql.model.js');

// Node tries to resolve ad.graphql.model.js
const userModule = require('user.graphql.model.js');
// Ups, this one has been resolved already and required this as dependency.
// We have no other choice than to assign an empty object here
// userModule is {}
const user =  {
  type: userModule.UserType, // undefined
  resolve(parentValue, args) {
    return UserSchema.findById(parentValue.user);
  }
};
// finish this module and return to user.graphql.model.js
// adModule now contains the resolved module
const adModule = require('ad.graphql.model.js');
// finish module and replace {} with actual module content in ad.graphql.model.js
// userModule contains UserType
const userModule = require('user.graphql.model.js');

const ads = {
  type: new GraphQLList(asModule.AdType), // GraphQLObjectType
}

// Now your Schema does build/inits itself after the config has been specified
// (and all modules have been resolved)
// imagine user being a function now taht is called on Schema init
const user = () => ({
  type: userModule.UserType, // GraphQLObjectType
  /* ... */
})

【讨论】:

  • 我的意思是我使用 () => ( { } ) 作为字段,因为当我使用字段时我的代码已经损坏:{ user: .... } 语法,因为它导致循环依赖,所以我已经修复了它。我不明白为什么只有 UserType 会产生这个问题,而不是 CategoryType、SubcategoryType 和其他以与 UserType 相同的方式导入的问题。我决定以这种方式构建我的代码,因为我希望代码会增长很多,所以我不想以后陷入混乱的代码中。
  • 是的,但是如果你不引用函数调用的inside,仅仅使用函数参数并不能解决问题。完成变量解析需要时间,但如果您需要,我可以在答案中写下来。
  • 我不确定我是否完全理解您在最后一条评论中要说的内容。定义 const user = () => ({ type... }) 有效,我理解它有效,因为它在执行 const AdType = ... 时执行代码。我不明白为什么只有 UserType 会出现这个问题。在用户模型中,我以相同的方式引用 AdType,它没有产生任何问题。我还在使用 CategoryType 和 SubcategoryType,它们的结构相同,只是使用不同的数据,而且没有窃听。
  • 你的category和subcategory不一样,它们使用的是调用时创建对象的函数定义。为什么只有一种类型未定义是因为它们解析模块的方式。我在我的帖子的编辑中写了这个。
  • 谢谢,这让我更清楚了。我不知道 require 模块解析是这样工作的。非常感谢您的帮助!有没有比使用函数返回更优雅的方法来解决这个问题?
猜你喜欢
  • 2017-08-16
  • 2018-06-30
  • 2019-12-23
  • 2016-06-29
  • 2017-12-12
  • 2018-12-18
  • 2019-09-19
  • 2017-09-21
  • 2017-09-03
相关资源
最近更新 更多