如何使用 GraphQL Relay 连接修复循环依赖

Posted

技术标签:

【中文标题】如何使用 GraphQL Relay 连接修复循环依赖【英文标题】:How to fix circular dependency with GraphQL Relay connections 【发布时间】:2017-11-15 13:37:21 【问题描述】:

我已经将我的连接与它自己的文件分开,并且可以在我的根查询中使用它(当连接在类型中定义时它工作正常),但是当尝试通过将它导入到类型来使用它时,连接是因为我刚回来:

错误:PageEdge.node 字段类型必须是输出类型但得到:未定义

我可以让连接在我的 QueryType 中工作,但不是 PageType。我的架构大致是这样的。

QueryType 
  pages: [PageType]


PageType 
  _id: string
  pages: [PageType]

这是一个指向graphql东西所在的项目repo的链接(我刚刚推送了一个提交,它出错以查看所有代码): https://github.com/DaveyEdwards/myiworlds/tree/master/src/data

我已经制作了 QueryType 和 PageType 字段 thunk(似乎可以解决大多数人的问题的解决方案)并且还尝试从接口中制作一个 thunk:

interfaces: () => [nodeInterface]

我认为对于任何与用户和朋友一起构建应用程序的人来说,这是一个非常常见的问题。

UserType: 
  friends: [UserType]

我的页面类型:

import  nodeInterface  from '../nodeInterface';
import PageConnection from './connections/PageConnection';

const PageType = new ObjectType(
  name: 'Page',
  description: 'Everything you see can be placed inside a page.',
  fields: () => (
    id: globalIdField('Page', page => page._id),
    _id: 
      type: new NonNull(ID),
      description: 'A unique id used to instantly locate this page inside the database',
    ,
    pageEdge: 
      type: PageConnection,
      args: connectionArgs,
      resolve: async (page,  args ,  loaders ) => 
        if (page.pageEdge) 
          const pageEdge = await loaders.pageLoader.loadMany(page.pageEdge);
          const connection = connectionFromArray(pageEdge, args);
          return connection;
        
      ,
    ,
  ),
  interfaces: () => [nodeInterface],
);

export default PageType;

我的页面连接:

import  connectionDefinitions  from 'graphql-relay';

import PageType from '../PageType';

const  connectionType: PageConnection  = connectionDefinitions(
  name: 'Page',
  nodeType: PageType,
);

export default PageConnection;

我的节点界面:

import  nodeDefinitions  from 'graphql-relay';
import  getNode, getNodeType  from './type-registry';

export const  nodeInterface, nodeField  = nodeDefinitions(getNode, getNodeType);

我的类型注册表:

import  fromGlobalId  from 'graphql-relay';
require('babel-polyfill');

const types = ;

export const registerType = (model, type, lookupFn) => 
  types[type.name] =  model, type, lookupFn ;
;

export const getNode = async (globalId) => 
  const  type: typeName, id  = fromGlobalId(globalId);
  console.log('getNode', globalId, typeName, id);

  if (types[typeName]) 
    const object1 = await types[typeName].lookupFn(id);
    const Class = types[typeName].model;
    // let result  = Object.create(types[typeName].model, object1);
    const result = new Class(object1);
    console.log('getNode result', result);
    return result;
  
  return null;
;

export const getNodeType = (obj) => 
  const keys = Object.keys(types);
  let ret = null;
  keys.map((typeName) => 
    if (obj instanceof types[typeName].model) 
      ret = types[typeName].type;
    
    return true;
  );
  return ret;
;

导入的连接工作的我的 QueryType

import 
  GraphQLObjectType as ObjectType,
  GraphQLList as List,
  GraphQLString as StringType,
 from 'graphql';
import  connectionArgs, connectionFromArray, connectionDefinitions  from 'graphql-relay';
import  nodeField  from '../nodeInterface';
import PageType from './PageType';
import  getPageList  from '../queries/googleDatastore/pageQueries';
import PageConnection from './connections/PageConnection';

const QueryType = new ObjectType(
  name: 'QueryType',
  fields: () => (
    pages: 
      type: PageConnection,
      args: connectionArgs,
      resolve: async (obj, args) => 
        const response = [];
        try 
          const pageEdge = await getPageList();
          const connection = connectionFromArray(pageEdge, args);
          return connection;
         catch (err) 
          console.log('pages err', err);
        
        return response;
      ,
    ,
    node: nodeField,
  ),
);

export default QueryType;

我一直在努力解决这个问题的资源:

这个 repo 的一部分是我为了让连接首先工作而实现的 https://github.com/bondz/learn-graphql-relay/blob/47211fdec44ce4bb10f487bddfc7411e5690b894/src/types/projectConnection.js

Edge.node field type must be Output Type but got: undefined

https://github.com/graphql/graphql-js/issues/612

https://github.com/graphql/graphql-js/issues/373

https://gist.github.com/fbaiodias/77406c29ddf37fe46c3c

【问题讨论】:

【参考方案1】:

只需删除 PageType.js 顶部的 import PageConnection 并使用运行时要求:

...
pageEdge: 
  type: require('./connections/PageConnection'),
  args: connectionArgs,
...

【讨论】:

返回错误:Page.pageEdge 字段类型必须为输出类型,但得到:[object Object]。 还尝试将 require 放入函数并调用类型: pages() 和 pages()[0/1] 仍然没有 试试require('./connections/PageConnection').default 天啊,非常感谢你们!!!!花了超过 3 天的时间来解决这个问题,并且正准备将连接放回类型中。我还必须再添加一件事,因为它给了我“无法在未定义之后读取属性”。我在 resolve 方法中用 ...args 替换了 args 并修复了它 在看到这个解决方案之前,我快要发疯了。拯救了我的一天,谢谢。

以上是关于如何使用 GraphQL Relay 连接修复循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL、Relay 和 Mongodb (mongoose) 如何获取数组

GraphQL 和 Relay 中的模式之间的区别

Relay/GraphQL 将自定义字段添加到连接

如何将 Realm 与 Relay/GraphQL 一起使用

GraphQL + Relay:如何执行重新获取授权?

GraphQL Relay Mutation Config RANGE_ADD 的 parentName 用于连接