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

I have confusion on relay and graphql resolve method

如果这是一个愚蠢的问题,我们深表歉意。这是让我感到困惑的 relay/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 解析的吗?我已经阅读了源文档(在本例中为 obj)- 从父类型的字段解析的对象。不是来自根查询吗?这里的obj是怎么创建的?

连接

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

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,您只有一种方法可以实际查询待办事项。由于 viewer 属于 GraphQLUser 类型,并且 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 将能够从 Root 中查询它们中的任何一个node 字段。