GraphQL开发:在UserType中定义BookType类型GraphQLList时出错求助
解决GraphQL中UserType与BookType循环引用导致的列表定义问题
嘿,这明显是循环引用搞的鬼!你想想,UserType要引用BookType,BookType又要引用UserType,Node.js加载模块的时候会因为这种互相依赖的顺序问题,导致其中一个类型在被引用的时候还没完全初始化好——所以直接在UserType里定义GraphQLList(BookType)就会报错,而BookType里的作者字段可能因为是单个类型,加载时机刚好没触发这个问题。
核心解决方案:用函数包裹类型的fields定义
GraphQL允许我们把fields写成一个返回对象的函数,而不是直接写对象。这样函数会在GraphQL实际需要解析字段的时候才执行,这时候两个类型都已经完成加载了,循环引用的问题就自然解决了。
修改你的user.js中的UserType:
const { GraphQLList, GraphQLID, GraphQLString, GraphQLObjectType } = require('graphql'); const BookType = require('./book'); const UserType = new GraphQLObjectType({ name: 'User', // 把fields改成函数,延迟求值 fields: () => ({ id: { type: GraphQLID }, name: { type: GraphQLString }, books: { type: new GraphQLList(BookType), resolve(parent, args) { // 这里写查询当前用户所有书籍的逻辑,比如: // return books.filter(book => book.authorId === parent.id); } } }) }); module.exports = UserType;
同时修改book.js中的BookType(保持一致性,避免后续问题):
const { GraphQLID, GraphQLString, GraphQLObjectType } = require('graphql'); const UserType = require('./user'); const BookType = new GraphQLObjectType({ name: 'Book', // 同样用函数包裹fields fields: () => ({ id: { type: GraphQLID }, title: { type: GraphQLString }, author: { type: UserType, resolve(parent, args) { // 这里写查询当前书籍对应作者的逻辑,比如: // return users.find(user => user.id === parent.authorId); } } }) }); module.exports = BookType;
为什么这样能解决问题?
Node.js处理循环引用时,会先给互相依赖的模块导出一个空的占位对象,然后继续执行模块内的代码。如果我们直接把fields写成对象,在模块加载阶段就会去引用另一个还没完全初始化的类型;而用函数包裹后,fields的实际定义会延迟到GraphQL执行查询的时候才被调用,这时候两个模块都已经执行完毕,类型都已经正确定义好了,自然就不会报错啦。
内容的提问来源于stack exchange,提问作者Lorenz
相关产品推荐
相关产品推荐

