解决Graphql中的类型

Boo*_*jaa 7 apollo graphql

GraphQL中有几个地方Type需要解析a 而不仅仅是a field中的a Type.

后端API -

  • /users - 用户列表 - 最小信息 - 名称,ID
  • /users/:id - 详细的用户信息
  • /foo - 返回一个UserID的字段所有者

查询和架构

构建模式以执行以下查询

query a {
  users {
    age # some detail info
  }
  foo {
    owner {
      location # some detail info
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

架构可以如下 -

type Query {
  users: [User]
  foo: Foo
}
type Foo {
  owner: User
}
type User {
  id: ID
  age: Int
  location: String
}
Run Code Online (Sandbox Code Playgroud)

问题

上述模式中的解析器需要在2个不同的位置包含/处理用户详细信息获取调用.1.用户列表 - Query.users和2 Query.foo.owner. 并且必须记住处理此类型,其中您只有用户ID将其转换为实际用户.

可能解决方案

在撰写本文时,GraphQL支持resolveTypeon InterfaceUnion.无法为整个指定一个解析器Type- 只有field一个Type可以有一个解析器.因此,如果可以在GraphQL中解析类型,这将使​​其更容易实现.

替代解决方案

由于只能解析Type中的字段,因此可以type在解析器中的Type中创建一个额外的字段并保持对该字段的处理,并且位于一个位置.但是现在,查询比以前更深了1级.

query b {
  users {
    details {
      age
    }
  }
  foo {
    owner {
      details {
        location
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

其他类似场景

由于Type无法在GraphQL中解决,因此enums面临同样的问题.当您在API响应中有一个特殊字符并且该字段是ENUM时,您要么记得在使用此枚举的所有位置处理它,要么创建一个额外的类型来表示此枚举.

我用ApolloGraphQL为所有这些案例创建了一个最小的repro - https://github.com/boopathi/graphql-test-1

问题

  1. 模式/语言是否不支持指定如何处理特定类型/为Type指定解析器而不仅仅是Type中的字段?如果没有,为什么?
  2. 如何在架构中处理这些事情.还有其他方法可以做这些事吗?

stu*_*ilo 4

你是对的——这在 GraphQL 中确实有点奇怪。本质上,由于解析器的工作方式,负责获取正确数据的是您来自的类型,而不是您将要使用的类型。

这种方法有优点也有缺点。您绝对可以想象 GraphQL 的一种实现,其中父对象仅返回一个 ID,然后每种类型都有一个知道如何获取详细信息的解析器。我认为这对于某些情况肯定会更好。

以下是我们目前建议构建代码以避免这种耦合的方式:

  1. 为您拥有的不同后端数据源和对象类型定义模型类或存储库对象
  2. 在解析器中使用它们,而不是直接访问数据库

为了实现穷人的依赖注入,我们将它们放在context服务器上。当你把它们放在一起时,它看起来像这样:

架构:

# Information about a GitHub repository submitted to GitHunt
type Entry {
  # Information about the repository from GitHub
  repository: Repository!
  # The GitHub user who submitted this entry
  postedBy: User!
  ...
Run Code Online (Sandbox Code Playgroud)

解析器:

export const resolvers = {
  Entry: {
    repository({ repository_name }, _, context) {
      return context.Repositories.getByFullName(repository_name);
    },
    postedBy({ posted_by }, _, context) {
      return context.Users.getByLogin(posted_by);
    },
    ...
Run Code Online (Sandbox Code Playgroud)

您可以在GitHunt-API示例应用程序的整个服务器的上下文中看到这一点。

基本上,这种方法使用解析器作为调用底层业务逻辑的瘦包装器,几乎就像路由器一样。这与当前有关Facebook其他服务器的文献是一致的。