У меня путаница с методом разрешения relay и graphql

Извиняюсь, если это глупый вопрос. это код для разбивки на страницы 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 есть текстовые и полные поля с функцией разрешения, переданной параметром obj, как туда передается obj? это от решения GraphQLUser? Я читал в документации, что источник (в данном случае obj) - объект, разрешенный из поля родительского типа. это не из корневого запроса? как здесь создается obj?


person gpbaculio    schedule 12.04.2017    source источник


Ответы (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, и мы уже указали в определениях соединения, что узлами являются GraphQLTodo, GraphQL знает, что поля text и complete разрешаются путем получения (в данном случае) полей с одинаковыми именами для возвращенных объектов. Другими словами, возвращаемый объект передается методу resolve для каждого поля.

Запрос корня

У вас есть два поля на Root: viewer и node. Не обращая внимания на node на мгновение, у вас есть только один способ запросить задачи. Поскольку viewer имеет тип GraphQLUser, а GraphQLUser имеет это поле todos, их можно получить только как подполе viewer, например:

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

Тайна узла

Но как насчет этого поля node? Relay хочет иметь возможность получать любой объект с помощью запроса верхнего уровня, то есть в вашем поле Root, когда ему задано уникальное значение globalId, которое представляет собой просто кодировку 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)
    }
...

Поскольку вы реализуете nodeInterface в обоих типах GraphQLTodo и GraphQLUser, Relay сможет запрашивать любой из них из поля Root node.

person Eric Streeper    schedule 15.04.2017
comment
Большое спасибо, я поделюсь вашим ответом на нашей странице сообщества (facebook). Надеюсь, мы сможем связаться с вами, @Eric Streeper - person gpbaculio; 15.04.2017