2017-03-01 169 views
2

我相当新的JavaScript,我目前正在学习使用Node.js实现一个MongoDB后端graphQL API。我遇到了两种类型之间的循环依赖问题。GraphQL循环依赖

基本上,我有一个经典的博客文章/博客作者的情况。一篇文章只有一位作者,因此猫鼬模式拥有对该作者的引用。

在我的graphQL类型“作者”中,我想添加一个字段“posts”,它允许我从作者导航到他们写的所有帖子。该引用不在数据库模型中编码,而是通过控制器检索。这是我的博客帖子代码。

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) 
      } 
     } 
    } 
}); 

目前正处在这里两件事情,我已经尝试过:

  1. 我使用的函数返回的字段场。我认为这被称为thunk或封闭。
  2. 我需要在返回字段的函数中使用PostType。当我需要文件./post和其他需要的时候,错误已经被扔在文件的顶部。

当我尝试运行此服务器的例子,我收到的错误:

Can only create List of a GraphQLType but got: [object Object]. 

它指向作家行

type: new graphql.GraphQLList(PostType) 

包含上面贴的类型定义还出口查询,像这样的文件:

var PostQuery = { 
    posts: { 
     type: new graphql.GraphQLList(PostType), 
     description: "Posts of this Blog", 
     resolve: PostResolvers.ret 
    } 
}; 

的职位像这样

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 
+0

如果您尝试定义像fields:()=>({_id:...,author:...})这样的字段,会发生什么? – piotrbienias

+0

然后,我必须在文件的顶部放置'var PostType = require(“./post”);'而不是在另一个类中获取错误。然后,输出是'PostType.author字段类型必须是输出类型,但得到:undefined.'并奇怪地指向GraphQL模式的生成。 – Bastian

+0

如果我然后添加另一个函数来检索PostType中的字段并使用您定义的函数,则会引发相同的错误。 – Bastian

回答

4

这是相当模块的典型问题循环依赖 - 你可以参考这个问题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实例。

+0

非常感谢。 PostType确实是我固定的一种类型。但这不是问题。你的链接让我得到了正确的答案:确保在任何需要的语句导入任何内容之前定义你的导出。 (我是释义)非常感谢。 – Bastian

3

piotrbienias的回应使我得到了正确的线索。我以前读过它,但完全不理解。在您需要课程之前,有必要定义出口。在我的情况下,我能够像这样修复它:

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之前定义了导出。

非常感谢!

+2

这是我的解决方案 - 关键是对'fields'参数使用回调函数,并将您的require()放入该函数中 –

+0

这是一种称为“thunk”的模式。 –