GraphQL 循环依赖
GraphQL circular dependency
我是 javascript 的新手,目前正在学习使用 Node.js 实现具有 MongoDB 后端的 graphQL API。我 运行 遇到了两种类型之间循环依赖的问题。
基本上我有一个经典博客post/blog作者的情况。 post 只有一位作者,因此 mongoose 模式包含对该作者的引用。
在我的 graphQL 类型 "Author" 中,我想添加一个字段 "posts",它允许我从作者导航到他们所写的所有 post。该引用未在数据库模型中编码,而是通过控制器检索。这是我的博客 post 代码。
var graphql = require("graphql");
var AuthorResolvers = require("../resolvers/author");
var PostResolvers = require("../resolvers/post");
var AuthorType = require("./author").AuthorType;
var PostType = new graphql.GraphQLObjectType({
name: "PostType",
fields: {
_id: {
type: graphql.GraphQLID
},
title: {
type: graphql.GraphQLString
},
author: {
type: AuthorType,
description: "Author of this post",
resolve: (post) => AuthorResolvers.retwArgs(post)
}
}
});
module.exports = {PostType};
resolvers.js 文件仅导出用于寻址控制器的函数。
我的作者类型定义如下:
var graphql = require ("graphql");
var AuthorResolvers = require("../resolvers/author");
var PostResolvers = require("../resolvers/post");
var AuthorType = new graphql.GraphQLObjectType({
name: "AuthorType",
fields: () => {
var PostType = require("./post");
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts written by this author",
resolve: (author) => PostResolvers.retwArgs(author)
}
}
}
});
这里有两件事我已经试过了:
- 我使用了一个函数来 return fields 字段。我认为这称为 thunk 或闭包。
- 我需要 return 函数中的 PostType 字段。当我需要文件 ./post 和其他要求时,错误已经抛出在文件的顶部。
当我尝试 运行 这个服务器示例时,我收到错误:
Can only create List of a GraphQLType but got: [object Object].
指向直线
type: new graphql.GraphQLList(PostType)
在作者中。
包含上述类型定义 post 的文件也导出这样的查询:
var PostQuery = {
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts of this Blog",
resolve: PostResolvers.ret
}
};
对于 post 和这样
var AuthorQuery = {
authors: {
type: new graphql.GraphQLList(AuthorType),
description: "The authors working on this Blog",
resolve: AuthorResolvers.ret
}
};
分别为作者。所有内容都集中在一个架构文件中,如下所示:
var graphql = require("graphql");
var Author = require("./types/author").AuthorQuery;
var Post = require("./types/post").PostQuery;
var root_query = new graphql.GraphQLObjectType({
name: "root_query",
fields: {
posts: Post.posts,
authors: Author.authors
}
});
module.exports = new graphql.GraphQLSchema({
query: root_query
});
最后是服务器:
var graphql = require ('graphql').graphql
var express = require('express')
var graphQLHTTP = require('express-graphql')
var Schema = require('./api/schema')
var app = express()
.use("/", graphQLHTTP(
{
schema: Schema,
pretty: true,
graphiql: true,
}
))
.listen(4000, function(err) {
console.log('Running a GraphQL API server at localhost:4000');
})
我真的看不出有什么办法可以解决这种循环依赖。如果我简单地注释掉 AuthorType 定义中对 PostType 的引用,服务器将毫无问题地启动。如有任何帮助,我们将不胜感激。
也许是为了更好地理解。目录结构如下所示:
│ package.json
│ server.js
│
├───api
│ │ schema.js
│ │
│ ├───controllers
│ │ author.js
│ │ post.js
│ │
│ ├───models
│ │ author.js
│ │ post.js
│ │
│ ├───resolvers
│ │ author.js
│ │ post.js
│ │
│ └───types
│ author.js
│ post.js
│
└───config
db.js
这是比较典型的模块循环依赖问题,可以参考这个问题How to deal with cyclic dependencies in Node.js。在这种情况下,它与 GraphQL 无关。
更何况,你做了module.exports = { PostType }
,然而在AuthorType
你执行了var PostType = require('./post')
,不应该是var PostType = require('./post').PostType
吗?我想这是你得到以下错误的原因:
Can only create List of a GraphQLType but got: [object Object].
因为您的 PostType
现在是 { PostType: ... }
而不是 GraphQLObjectType
实例。
piotrbienias 的回复让我找到了正确的话题。我以前读过,但没有完全理解。在需要 class 之前,有必要定义导出。就我而言,我能够像这样修复它:
module.exports.AuthorType = new graphql.GraphQLObjectType({
name: "AuthorType",
fields: () => {
var PostType = require("./post").PostType;
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts written by this author",
resolve: (author) => PostResolvers.retwArgs(author)
}
}
}
});
对于 PostType 也是如此。这样,在调用 require 之前定义导出。
非常感谢!
根据 this article,graphQL 确实在一定程度上增加了循环依赖的问题。文章建议使用 extend type
来定义相互依赖的类型。它对我有效。
因此,不用 'staightforward' 方式定义类型:
type User {
id: ID
posts: [Post]
}
type Post {
id: ID
user: User
}
您应该使用单向定义,然后使用 extend
添加另一个依赖方向,如下所示:
type User {
id: ID
// no reference to [Post] !
}
type Post {
id: ID
user: User // this stays - single direction
}
extend type User {
posts: [Post]
}
有关理由和更详细的示例,请参阅文章。
我是 javascript 的新手,目前正在学习使用 Node.js 实现具有 MongoDB 后端的 graphQL API。我 运行 遇到了两种类型之间循环依赖的问题。
基本上我有一个经典博客post/blog作者的情况。 post 只有一位作者,因此 mongoose 模式包含对该作者的引用。
在我的 graphQL 类型 "Author" 中,我想添加一个字段 "posts",它允许我从作者导航到他们所写的所有 post。该引用未在数据库模型中编码,而是通过控制器检索。这是我的博客 post 代码。
var graphql = require("graphql");
var AuthorResolvers = require("../resolvers/author");
var PostResolvers = require("../resolvers/post");
var AuthorType = require("./author").AuthorType;
var PostType = new graphql.GraphQLObjectType({
name: "PostType",
fields: {
_id: {
type: graphql.GraphQLID
},
title: {
type: graphql.GraphQLString
},
author: {
type: AuthorType,
description: "Author of this post",
resolve: (post) => AuthorResolvers.retwArgs(post)
}
}
});
module.exports = {PostType};
resolvers.js 文件仅导出用于寻址控制器的函数。
我的作者类型定义如下:
var graphql = require ("graphql");
var AuthorResolvers = require("../resolvers/author");
var PostResolvers = require("../resolvers/post");
var AuthorType = new graphql.GraphQLObjectType({
name: "AuthorType",
fields: () => {
var PostType = require("./post");
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts written by this author",
resolve: (author) => PostResolvers.retwArgs(author)
}
}
}
});
这里有两件事我已经试过了:
- 我使用了一个函数来 return fields 字段。我认为这称为 thunk 或闭包。
- 我需要 return 函数中的 PostType 字段。当我需要文件 ./post 和其他要求时,错误已经抛出在文件的顶部。
当我尝试 运行 这个服务器示例时,我收到错误:
Can only create List of a GraphQLType but got: [object Object].
指向直线
type: new graphql.GraphQLList(PostType)
在作者中。
包含上述类型定义 post 的文件也导出这样的查询:
var PostQuery = {
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts of this Blog",
resolve: PostResolvers.ret
}
};
对于 post 和这样
var AuthorQuery = {
authors: {
type: new graphql.GraphQLList(AuthorType),
description: "The authors working on this Blog",
resolve: AuthorResolvers.ret
}
};
分别为作者。所有内容都集中在一个架构文件中,如下所示:
var graphql = require("graphql");
var Author = require("./types/author").AuthorQuery;
var Post = require("./types/post").PostQuery;
var root_query = new graphql.GraphQLObjectType({
name: "root_query",
fields: {
posts: Post.posts,
authors: Author.authors
}
});
module.exports = new graphql.GraphQLSchema({
query: root_query
});
最后是服务器:
var graphql = require ('graphql').graphql
var express = require('express')
var graphQLHTTP = require('express-graphql')
var Schema = require('./api/schema')
var app = express()
.use("/", graphQLHTTP(
{
schema: Schema,
pretty: true,
graphiql: true,
}
))
.listen(4000, function(err) {
console.log('Running a GraphQL API server at localhost:4000');
})
我真的看不出有什么办法可以解决这种循环依赖。如果我简单地注释掉 AuthorType 定义中对 PostType 的引用,服务器将毫无问题地启动。如有任何帮助,我们将不胜感激。
也许是为了更好地理解。目录结构如下所示:
│ package.json
│ server.js
│
├───api
│ │ schema.js
│ │
│ ├───controllers
│ │ author.js
│ │ post.js
│ │
│ ├───models
│ │ author.js
│ │ post.js
│ │
│ ├───resolvers
│ │ author.js
│ │ post.js
│ │
│ └───types
│ author.js
│ post.js
│
└───config
db.js
这是比较典型的模块循环依赖问题,可以参考这个问题How to deal with cyclic dependencies in Node.js。在这种情况下,它与 GraphQL 无关。
更何况,你做了module.exports = { PostType }
,然而在AuthorType
你执行了var PostType = require('./post')
,不应该是var PostType = require('./post').PostType
吗?我想这是你得到以下错误的原因:
Can only create List of a GraphQLType but got: [object Object].
因为您的 PostType
现在是 { PostType: ... }
而不是 GraphQLObjectType
实例。
piotrbienias 的回复让我找到了正确的话题。我以前读过,但没有完全理解。在需要 class 之前,有必要定义导出。就我而言,我能够像这样修复它:
module.exports.AuthorType = new graphql.GraphQLObjectType({
name: "AuthorType",
fields: () => {
var PostType = require("./post").PostType;
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
posts: {
type: new graphql.GraphQLList(PostType),
description: "Posts written by this author",
resolve: (author) => PostResolvers.retwArgs(author)
}
}
}
});
对于 PostType 也是如此。这样,在调用 require 之前定义导出。
非常感谢!
根据 this article,graphQL 确实在一定程度上增加了循环依赖的问题。文章建议使用 extend type
来定义相互依赖的类型。它对我有效。
因此,不用 'staightforward' 方式定义类型:
type User {
id: ID
posts: [Post]
}
type Post {
id: ID
user: User
}
您应该使用单向定义,然后使用 extend
添加另一个依赖方向,如下所示:
type User {
id: ID
// no reference to [Post] !
}
type Post {
id: ID
user: User // this stays - single direction
}
extend type User {
posts: [Post]
}
有关理由和更详细的示例,请参阅文章。