节点 - 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 字段

Graphql 字段上的未知参数

部分更新突变(GraphQL)

使用 join-monster 库 (GraphQL) 对根查询字段进行分页

如何使用GraphQL在MERN应用程序的MongoDB模式中插入数组字段?

使用 ApolloWebserver 时无法在 GraphQL 架构中使用 @cypher