Node.js 如何实现isTypeOf方法?

Node.js 如何实现isTypeOf方法?,node.js,typescript,express,graphql,express-graphql,Node.js,Typescript,Express,Graphql,Express Graphql,鉴于此模式: 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: a

鉴于此模式:

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和expressgraphql
isTypeOf
是一个函数,当您以编程方式创建模式时,它会传递给GraphQLObjectType的构造函数。
resolveType
函数和联合/接口也一样。如果您使用SDL并使用
buildSchema
创建模式,则无法将这些函数注入到创建的模式中,就像您无法为除
Query
Mutation
之外的类型上的字段提供解析程序一样

你有两个选择。一个选项是利用默认的
resolveType
行为。这将检查对象上的
\uuu typename
属性,并返回到对每个实现类型调用
isTypeOf
,直到它匹配为止。这意味着,如果您正在使用一个类,执行以下操作就足够了:

export default class Todo {
  get __typename() {
    return 'Todo'
  }
}
const resolvers = {
  Query: {
    node: (obj, args, context, info) => {
      return new Todo('1', 'Todo 1')
    }
  },
  Todo: {
    __isTypeOf: (obj, context, info) => {
      return obj instanceof Todo
    },
  }
}
更好的选择是删除
buildSchema
并使用
graphql工具中的
makeExecutableSchema
。然后可以直接在解析器中定义
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
,则解析程序的外观如下所示:

export default class Todo {
  get __typename() {
    return 'Todo'
  }
}
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

Daniel,感谢您抽出时间。我尝试了第一个建议,但没有效果,所以现在我考虑继续你的第二个建议:使用
makeExecutableSchema
。然而,我有一个担忧。我试图创建一个中继服务器,
makeExecutableSchema
来自Apollo。到目前为止,我知道中继是一种“模式”,而阿波罗是一种具有不同实现的“框架”。所以我的问题是:在同一个解决方案中使用这两种方法不是不正确吗?如果您希望集成
graphql-relay-js
,以制作符合中继的服务器,我相信,强制您使用vanilla GraphQL.js以编程方式生成模式——使用
buildSchema
makeExecutableSchema
从SDL构建模式可能不允许您合并中继库中包含的所有各种帮助器方法。否则,就有可能用graphql工具甚至apollo服务器构建一个中继兼容服务器?你看到了什么错误或行为?这里有一个使用Launchpad的工作示例,演示了我的建议:(Launchpad使用makeExecutableSchema,但概念仍然是一样的)“如果您希望集成graphql中继js以创建符合中继的服务器,我相信这会迫使您使用vanilla graphql.js以编程方式生成模式”-这正是我想要做的答案是否可以更新为包含isTypeOf实现?这是最初的问题,但它似乎并不能真正解释这一点。