Как реализовать метод isTypeOf?

Учитывая эту схему:

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, но все еще получаю сообщение об ошибке.

Что я делаю неправильно?

Примечания:

  • Я использую Typescript, express и express-graphql;
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
8 998
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 для каждого типа объекта, который может быть абстрактным типом.

Дэниел, спасибо за уделенное время. Я попробовал первое предложение, но оно не сработало, поэтому сейчас я рассматриваю возможность перейти к вашему второму предложению: используйте makeExecutableSchema. Однако у меня есть одно беспокойство. Я пытаюсь создать сервер ретрансляции, а makeExecutableSchema от Apollo. Насколько я знаю, Relay - это «шаблон», а Apollo - это «каркас» с другой реализацией. Итак, мой вопрос: не было бы неправильным использовать оба в одном решении?

Saulo 04.11.2018 10:28

Если вы хотите интегрировать graphql-relay-js для создания сервера, совместимого с реле, я считаю, что это заставляет вас программно генерировать схему с использованием vanilla GraphQL.js - построение схемы из SDL с использованием buildSchema или makeExecutableSchema, вероятно, не позволит вам включить все различные вспомогательные методы, включенные в библиотеку реле. В противном случае можно создать сервер, совместимый с реле, с помощью инструментов graphql или даже apollo-server.

Daniel Rearden 04.11.2018 13:16

Мне любопытно, что насчет первого подхода «не работает»? Какие ошибки или поведение вы видели? Вот рабочий пример с использованием Launchpad, который демонстрирует то, что я предлагал: launchpad.graphql.com/07wkrx5qj5 (Launchpad использует makeExecutableSchema, но концепция все та же)

Daniel Rearden 04.11.2018 13:17

«Если вы хотите интегрировать graphql-relay-js для создания сервера, совместимого с реле, я считаю, что это заставляет вас программно генерировать схему с использованием vanilla GraphQL.js» - именно это я и пытаюсь сделать! знак равно

Saulo 05.11.2018 07:59

Что касается ошибки, то это моя ошибка: я изменил только реализацию класса todo и сохранил его, используя buildSchema из 'graphql.js' (не makeExecutableSchema из 'graphql-tools'). Я буду продолжать пытаться понять, как реализовать сервер ретрансляции с помощью vanilla GraphQL!

Saulo 05.11.2018 08:03

Можно ли обновить ответ, включив в него реализацию isTypeOf? Это был первоначальный вопрос, но, похоже, он этого не объясняет.

justin.m.chase 13.09.2019 22:20

Другие вопросы по теме