Учитывая эту схему:
interface INode {
id: ID
}
type Todo implements INode {
id: ID
title: String!
}
type Query {
node(id: ID!): INode
}
Учитывая этот класс:
export default class Todo {
constructor (public id: string, public title: string) { }
isTypeOf(value: any): Boolean {
return value instanceof Todo;
}
}
Учитывая этот преобразователь:
type NodeArgs = {
id: string
}
export const resolver = {
node: ({ id }: NodeArgs) => {
return new Todo('1', 'Todo 1');
}
}
Когда я вызываю запрос:
query {
node(id: "1") {
id
... on Todo {
title
}
}
}
Затем я получаю результат ниже:
{
"errors": [
{
"message": "Abstract type INode must resolve to an Object type at runtime for field Query.node with value { id: \"1\", title: \"Todo 1\" }, received \"undefined\". Either the INode type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"node"
]
}
],
"data": {
"node": null
}
}
Как видите, я реализовал функцию isTypeOf, но все еще получаю сообщение об ошибке.
Что я делаю неправильно?
Примечания:





isTypeOf - это функция, которая передается конструктору GraphQLObjectType при программном создании схемы. То же самое для функций и объединений / интерфейсов resolveType. Если вы используете SDL и создаете свою схему с помощью buildSchema, нет способа внедрить эти функции в созданную схему, точно так же, как у вас нет способа предоставить преобразователи для полей типов, отличных от Query и Mutation.
У вас есть несколько вариантов. Один из вариантов - использовать поведение resolveType по умолчанию. Это проверяет свойство __typename на объекте и возвращается к вызову isTypeOf для каждого типа реализации, пока он не будет соответствовать. Это означает, что если вы используете класс, этого должно быть достаточно сделать что-то вроде этого:
export default class Todo {
get __typename() {
return 'Todo'
}
}
Лучшим вариантом было бы отказаться от buildSchema и использовать makeExecutableSchema из graphql-tools. Затем вы можете определить свои функции resolveType и / или isTypeOf прямо в ваших резолверах. Например:
const resolvers = {
Query: {
node: (obj, args, context, info) => {
return new Todo('1', 'Todo 1')
}
},
INode: {
__resolveType: (obj, context, info) => {
if (obj instanceof Todo) return 'Todo'
},
}
}
Таким образом вы можете не только легко определить isTypeOf или resolveType, но и легко добавить преобразователи для полей любого типа и добавить пользовательские скаляры без каких-либо проблем. Вы не можете сделать ничего из этого (легко), если используете только buildSchema.
Редактировать:
Если вы предпочитаете использовать isTypeOf вместо resolveType, резолверы будут выглядеть примерно так:
const resolvers = {
Query: {
node: (obj, args, context, info) => {
return new Todo('1', 'Todo 1')
}
},
Todo: {
__isTypeOf: (obj, context, info) => {
return obj instanceof Todo
},
}
}
Необходимо только одно или другое. Либо напишите функцию resolveType для каждого используемого абстрактного типа, либо или напишите isTypeOf для каждого типа объекта, который может быть абстрактным типом.
Если вы хотите интегрировать graphql-relay-js для создания сервера, совместимого с реле, я считаю, что это заставляет вас программно генерировать схему с использованием vanilla GraphQL.js - построение схемы из SDL с использованием buildSchema или makeExecutableSchema, вероятно, не позволит вам включить все различные вспомогательные методы, включенные в библиотеку реле. В противном случае можно создать сервер, совместимый с реле, с помощью инструментов graphql или даже apollo-server.
Мне любопытно, что насчет первого подхода «не работает»? Какие ошибки или поведение вы видели? Вот рабочий пример с использованием Launchpad, который демонстрирует то, что я предлагал: launchpad.graphql.com/07wkrx5qj5 (Launchpad использует makeExecutableSchema, но концепция все та же)
«Если вы хотите интегрировать graphql-relay-js для создания сервера, совместимого с реле, я считаю, что это заставляет вас программно генерировать схему с использованием vanilla GraphQL.js» - именно это я и пытаюсь сделать! знак равно
Что касается ошибки, то это моя ошибка: я изменил только реализацию класса todo и сохранил его, используя buildSchema из 'graphql.js' (не makeExecutableSchema из 'graphql-tools'). Я буду продолжать пытаться понять, как реализовать сервер ретрансляции с помощью vanilla GraphQL!
Можно ли обновить ответ, включив в него реализацию isTypeOf? Это был первоначальный вопрос, но, похоже, он этого не объясняет.
Дэниел, спасибо за уделенное время. Я попробовал первое предложение, но оно не сработало, поэтому сейчас я рассматриваю возможность перейти к вашему второму предложению: используйте
makeExecutableSchema. Однако у меня есть одно беспокойство. Я пытаюсь создать сервер ретрансляции, аmakeExecutableSchemaот Apollo. Насколько я знаю, Relay - это «шаблон», а Apollo - это «каркас» с другой реализацией. Итак, мой вопрос: не было бы неправильным использовать оба в одном решении?