【问题标题】:How to implement isTypeOf method?如何实现 isTypeOf 方法?
【发布时间】:2019-04-04 08:03:53
【问题描述】:

鉴于此架构:

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;

【问题讨论】:

    标签: node.js typescript express graphql express-graphql


    【解决方案1】:

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

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

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

    更好的选择是删除buildSchema 并使用graphql-tools 中的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'
        },
      }
    }
    

    您不仅可以通过这种方式轻松定义isTypeOfresolveType,还可以轻松为任何类型的字段添加解析器并轻松添加自定义标量。如果您只使用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 是一个具有不同实现的“框架”。所以我的问题是:在同一个解决方案中使用两者不会不正确吗?
    • 如果您希望集成 graphql-relay-js 以创建一个符合中继标准的服务器,我相信这会迫使您使用 vanilla GraphQL.js 以编程方式生成架构——使用任一 @ 从 SDL 构建架构987654348@ 或 makeExecutableSchema 可能不会让您合并中继库中包含的所有各种帮助方法。否则,可以使用 graphql-tools 甚至 apollo-server 构建一个符合中继的服务器。
    • 我很好奇第一种方法“行不通”呢?你看到了什么错误或行为?这是一个使用 Launchpad 的工作示例,它演示了我的建议:launchpad.graphql.com/07wkrx5qj5(Launchpad 使用 makeExecutableSchema,但概念仍然相同)
    • “如果您希望集成 graphql-relay-js 以制作符合中继的服务器,我相信这会迫使您使用 vanilla GraphQL.js 以编程方式生成模式” - 这正是我努力去做! =)
    • 可以更新答案以包含 isTypeOf 实现吗?那是最初的问题,但实际上似乎并没有这样解释。
    猜你喜欢
    • 2014-10-17
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多