2017-03-01 168 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」的模式。 –