我对中继和graphql解析方法感到困惑

Posted

技术标签:

【中文标题】我对中继和graphql解析方法感到困惑【英文标题】:I have confusion on relay and graphql resolve method 【发布时间】:2017-09-08 19:06:39 【问题描述】:

抱歉,如果这是一个愚蠢的问题。这是令我困惑的中继/graphql 分页代码:

const GraphQLTodo = new GraphQLObjectType(
  name: 'Todo',
  fields: 
    id: globalIdField('Todo'),
    text: 
      type: GraphQLString,
      resolve: (obj) => obj.text,
    ,
    complete: 
      type: GraphQLBoolean,
      resolve: (obj) => obj.complete,
    ,
  ,
  interfaces: [nodeInterface],
);

/* When pagination is needed, make a connection */ 
const 
  connectionType: TodosConnection,
  edgeType: GraphQLTodoEdge,
 = connectionDefinitions(
  name: 'Todo',
  nodeType: GraphQLTodo,
);

const GraphQLUser = new GraphQLObjectType(
  name: 'User',
  fields: 
    id: globalIdField('User'),
    todos: 
      type: TodosConnection,
      args: 
        status: 
          type: GraphQLString,
          defaultValue: 'any',
        ,
        ...connectionArgs,
      ,
      resolve: (obj, status, ...args) =>
        connectionFromArray(getTodos(status), args),
    ,
    totalCount: 
      type: GraphQLInt,
      resolve: () => getTodos().length,
    ,
    completedCount: 
      type: GraphQLInt,
      resolve: () => getTodos('completed').length,
    ,
  ,
  interfaces: [nodeInterface],
);
const Root = new GraphQLObjectType(
  name: 'Root',
  fields: 
    viewer: 
      type: GraphQLUser,
      resolve: () => getViewer(),
    ,
    node: nodeField,
  ,
);

你可以看到GraphQLTodo字段有text和complete字段,resolve函数传了一个obj参数,obj是怎么传到那里的?是由 GraphQLUser 解决的吗?我在文档上阅读了 source(在本例中为 obj) - 从父类型的字段解析的对象。不是来自根查询吗?这里的obj是怎么创建的?

【问题讨论】:

【参考方案1】:

连接

这里是(部分)魔法发生的地方:

const 
  connectionType: TodosConnection,
  edgeType: GraphQLTodoEdge,
 = connectionDefinitions(
  name: 'Todo',
  nodeType: GraphQLTodo,
);

您现在已经告诉 GraphQL,TodosConnection 将由 GraphQLTodo 节点组成。现在,让我们看看在GraphQLUser 对象中实际为连接获取对象的位置,该对象位于todos 字段中:

todos: 
  type: TodosConnection,
  args: 
    status: 
      type: GraphQLString,
      defaultValue: 'any',
    ,
    ...connectionArgs,
  ,
  resolve: (obj, status, ...args) =>
    connectionFromArray(getTodos(status), args),
,

那么这个对象是从哪里来的呢?这里的关键部分是getTodos 函数,它负责从数据源中实际获取对象数组。由于该字段是TodosConnection,并且我们已经在连接定义中指定节点是GraphQLTodos,GraphQL 知道textcomplete 字段是通过获取(在这种情况下)同名来解析的已返回的对象上的字段。换句话说,返回的对象被传递给每个字段的resolve 方法。

查询根目录

Root 上公开了两个字段:viewernode。暂时忽略node,您只有一种方法可以实际查询待办事项。由于viewerGraphQLUser 类型,而GraphQLUser 具有todos 字段,它们只能作为viewer 的子字段来获取,如下所示:


  viewer 
    todos(first: 10) 
      edges 
        # each node is a Todo item
        node 
          text
          complete
        
      
    
  

节点之谜

但是node 字段呢? Relay 希望能够使用***查询获取任何对象,即在您的Root 字段上,当给定一个唯一的globalId 时,它只是类型名称和id 的base64 编码,所以Todo:1编码为VG9kbzox。这是在nodeDefinitions 中设置的(您没有包括在此处,但可能有)。在这些定义中,globalId 被解析回type (Todo) 和id (1),然后再一次告诉它如何从数据源中获取正确的对象。它可能看起来像:

const  nodeInterface, nodeField  = nodeDefinitions(
  (globalId) => 
    const  type, id  = fromGlobalId(globalId);
    if (type === 'Todo') 
      return getTodo(id)
     else if (type === 'User') 
      return getUser(id)
    
...

因为您在 GraphQLTodoGraphQLUser 类型中都实现了 nodeInterface,所以 Relay 将能够从 Rootnode 字段中查询其中任何一个。

【讨论】:

非常感谢,我将在我们的社区页面(facebook)上分享您的答案我希望有一种方式可以与您联系@Eric Streeper

以上是关于我对中继和graphql解析方法感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL 和 MongoDB 游标

Prisma GraphQL-Yoga:解析器需要异步吗?

GraphQL,中继:处理错误

对 facebook graph api 升级感到困惑

C#中继承对象的内存分配

使用 Relay 和 GraphQL 进行查询