节点 - GraphQL - Ad.user 字段类型必须是输出类型,但得到:未定义
Posted
技术标签:
【中文标题】节点 - GraphQL - Ad.user 字段类型必须是输出类型,但得到:未定义【英文标题】:Node - GraphQL - Ad.user field type must be Output Type but got: undefined 【发布时间】: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: () => ( ) 来延迟加载字段以避免循环依赖的问题,所以这个问题真的很头疼。 【参考方案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 模块解析是这样工作的。非常感谢您的帮助!有没有比使用函数返回更优雅的方法来解决这个问题?以上是关于节点 - GraphQL - Ad.user 字段类型必须是输出类型,但得到:未定义的主要内容,如果未能解决你的问题,请参考以下文章
节点 express-graphql 应用程序中使用的 Prisma 2 DateTime 字段
使用 join-monster 库 (GraphQL) 对根查询字段进行分页