如何实现 isTypeOf 方法? [英] How to implement isTypeOf method?

查看:18
本文介绍了如何实现 isTypeOf 方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于此架构:

interface INode {身份证:身份证}类型 Todo 实现 INode {身份证:身份证标题:字符串!}类型查询{节点(ID:ID!):INode}

给定这个类:

导出默认类 Todo {构造函数(公共 ID:字符串,公共标题:字符串){ }isTypeOf(value: any): Boolean {返回值 instanceof Todo;}}

给定这个解析器:

type NodeArgs = {id:字符串}导出常量解析器 = {节点:({ id }:NodeArgs)=>{return new Todo('1', 'Todo 1');}}

当我调用查询时:

查询{节点(ID:1"){ID... 在 Todo {标题}}}

然后我得到以下回报:

<代码>{错误":[{"message": "抽象类型 INode 必须在运行时解析为字段 Query.node 的对象类型,其值为 { id: "1", title: "Todo 1" }, received "undefined".要么INode 类型应该提供一个 "resolveType" 函数或者每个可能的类型应该提供一个 "isTypeOf" 函数.",地点":[{线":2,列":3}],小路": [节点"]}],数据": {节点":空}}

如您所见,我已经实现了 isTypeOf 函数,但仍然收到错误消息.

我做错了什么?

注意事项:

  • 我正在使用 Typescript、express 和 express-graphql;

解决方案

isTypeOf 是以编程方式创建架构时传递给 GraphQLObjectType 构造函数的函数.resolveType 函数和联合/接口也是如此.如果您使用 SDL 并使用 buildSchema 创建架构,则无法将这些函数注入到您创建的架构中,就像您无法为 buildSchema 以外的类型的字段提供解析器一样code>Query 和 Mutation.

您有几个选择.一种选择是利用默认的 resolveType 行为.这会检查对象上的 __typename 属性,然后回退到在每个实现类型上调用 isTypeOf 直到匹配为止.这意味着如果您使用的是类,那么执行以下操作就足够了:

导出默认类 Todo {得到 __typename() {返回待办事项"}}

更好的选择是删除 buildSchema 并使用 graphql-tools 中的 makeExecutableSchema.然后您可以直接在解析器中定义 resolveType 和/或 isTypeOf 函数.例如:

const 解析器 = {询问: {节点:(对象,参数,上下文,信息)=>{return new Todo('1', 'Todo 1')}},节点:{__resolveType: (obj, context, info) =>{if (obj instanceof Todo) 返回 'Todo'},}}

您不仅可以通过这种方式轻松定义 isTypeOfresolveType,还可以轻松地为任何类型的字段添加解析器,并轻松添加自定义标量.如果您仅使用 buildSchema,则无法(轻松)执行任何操作.

如果你更喜欢使用 isTypeOf 而不是 resolveType,解析器看起来像这样:

const 解析器 = {询问: {节点:(对象,参数,上下文,信息)=>{return new Todo('1', 'Todo 1')}},去做: {__isTypeOf: (obj, context, info) =>{返回 obj 实例的 Todo},}}

只需要其中一个.要么为您使用的每个抽象类型编写一个 resolveType 函数,为每个可能是抽象类型的对象类型编写一个 isTypeOf.

Given this schema:

interface INode {
  id: ID
}

type Todo implements INode {
  id: ID
  title: String!
}

type Query {
  node(id: ID!): INode
}

Given this class:

export default class Todo {
  constructor (public id: string, public title: string) { }

  isTypeOf(value: any): Boolean {
    return value instanceof Todo;
  }
}

Given this resolver:

type NodeArgs = {
  id: string
}
export const resolver = {
  node: ({ id }: NodeArgs) => {
    return new Todo('1', 'Todo 1');
  }
}

When I call the query:

query {
  node(id: "1") {
    id
    ... on Todo {
      title
    }
  }
}

Then I get the return below:

{
  "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
  }
}

As you can see, I've implemented the isTypeOf function but I am still getting the error message.

What am I doing wrong?

Notes:

  • I am using Typescript, express and express-graphql;

解决方案

isTypeOf is a function that is passed to the constructor of a GraphQLObjectType when you create your schema programatically. Ditto for resolveType functions and unions/interfaces. If you use SDL and create your schema using buildSchema, there is no way to inject those functions into your created schema, just like you don't have a way to provide resolvers for fields on types other than Query and Mutation.

You have a couple of options. One option is to utilize the default resolveType behavior. This checks for a __typename property on the object, and falls back to calling isTypeOf on every implementing type until it matches. That means if you're using a class, it should be sufficient to do something like this:

export default class Todo {
  get __typename() {
    return 'Todo'
  }
}

The better option would be to drop buildSchema and use makeExecutableSchema from graphql-tools. Then you can define your resolveType and/or isTypeOf functions directly in your resolvers. For example:

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'
    },
  }
}

Not only can you easily define isTypeOf or resolveType this way, you can also easily add resolvers for fields of any type and add custom scalars without any hassle. You cannot do any of that (easily) if you're using just buildSchema.

Edit:

If you prefer to utilize isTypeOf instead of resolveType, the resolvers would look something like this:

const resolvers = {
  Query: {
    node: (obj, args, context, info) => {
      return new Todo('1', 'Todo 1')
    }
  },
  Todo: {
    __isTypeOf: (obj, context, info) => {
      return obj instanceof Todo
    },
  }
}

Only one or the other is necessary. Either write a resolveType function for every abstract type you use, or write a isTypeOf for every object type that could be an abstract type.

这篇关于如何实现 isTypeOf 方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆