是否可以在 GraphQL 中跨不同类型定义共享字段解析器?

问题描述 投票:0回答:1

我有一些类型本质上扩展了基本类型。我知道 GraphQL 并不完全支持这一点,所以我使用一个接口来定义基类,然后在基类型和扩展类型中实现它。它的好处是允许我使用共享片段。然而,我希望我可以在接口之外定义解析器,而不是在每个单独的类型中。有没有办法通过 GraphQL 本身定义共享解析器?

union Object = BaseObject | ObjectA | ObjectB

interface ObjectI {
  id: ID!
  relationalField: SomeOtherObject!
  ...
}

type BaseObject implements ObjectI {
  id: ID!
  relationalField: SomeOtherObject!
  ...
}

type ObjectA implements ObjectI {
  id: ID!
  relationalField: SomeOtherObject!
  ...
  # more fields
  uniqueA: String!
}

type ObjectB implements ObjectI {
  id: ID!
  relationalField: SomeOtherObject!
  ...
  # more fields
  uniqueB: String!
}
export const resolvers = {
  Query: {
    objects: async (parent, args, context, info) => dataSource.get(),
  },
  Object: {
    __resolveType: (obj) => defineType(obj),
  },
  ObjectI: {
    // this is what I am trying to do that doesn't work
    relationalField: async (parent, args, context, info) => dataSource.getSomeOtherObject(parent),
  },
  // instead I have to define that resolver 3 times in each type
  BaseObject: { },
  ObjectA: { }, 
  ObjectB: { },
}

我意识到我可以在其他地方创建一个在每个解析器中调用的函数变量。有用。但只是想知道是否有一种方法可以通过 GraphQL 层次结构来定义通用解析器?

:哎呀:

  BaseObject: {
    relationalField: async (parent, args, context, info) => dataSource.getSomeOtherObject(parent),
  },
  ObjectA: {
    relationalField: async (parent, args, context, info) => dataSource.getSomeOtherObject(parent),
  }, 
  ObjectB: {
    relationalField: async (parent, args, context, info) => dataSource.getSomeOtherObject(parent),
  },
graphql
1个回答
0
投票

“解析器”不是 GraphQL 问题。它们甚至不在 GraphQL 规范中。这是一个特定于实施的问题。这个问题与 GraphQL 无关,除了你问题前面的层是 GraphQL。

查看您的代码,我假设您正在使用 Apollo Server,这使得这是一个 JavaScript(或 TypeScript)问题,因此您可以做任何您想做的事情。您可以使用一些

GenericTypeResolver

 类。你可以做一个解析器工厂。

interface GenericResolvers<T> { loadById(id: string): T; loadAll(): T[]; deleteById(id: string): T; } type EntityModel = typeof User | typeof Book | typeof Author; const genericTypeResolverFactory = <T extends EntityModel>(model: T): GenericResolvers<T> => { const dataSource = new DataSource<T>(model); return { loadById: (id: string) => dataSource.loadById(id), loadAll: () => dataSource.loadAll(), deleteById: (id: string) => dataSource.deleteById(id), } } const resolvers = { User: genericTypeResolverFactory(User), Book: genericTypeResolverFactory(Book), Author: genericTypeResolverFactory(Author), }
甚至

const resolvers = [User, Book, Author].reduce((acc, model) => { acc[model.constructor.name] = genericTypeResolverFactory(model); return acc; }, {} as Record<string, GenericResolvers<EntityModel>>);


警告:根据您使用的 Apollo 或 graphql-js 的版本,您可能需要注意“额外字段”。如果您将类与其他方法一起使用,那么这些方法在功能上都是“解析器”,无论您是否有意为之,如果您的架构中没有属性的解析器,一些工具会抱怨。这就是为什么工厂有时比类更受青睐的原因之一。

© www.soinside.com 2019 - 2024. All rights reserved.