4

我使用以下约定让解析器返回部分数据,并允许其他解析器完成缺失的字段:

type UserExtra {
  name: String!
}

type User {
  id: ID!
  email: String!
  extra: UserExtra!
}

type Query {
  user(id: ID!): User!
  users: [User!]!
}
const getUser = (id: string): { id: string, email: string, extra: { name: string } => fetchUser(id);

// `fetchUsers` only returns `id` and `email`, but not `extra`
const getUsers = (): { id: string, email: string }[] => fetchUsers();

// we can use this function to fetch the extra field for a given user
const getUserExtra = (id: string): { name: string }  => fetchUserExtra();

export default {
  Query: {
    user: (parent, args) => getUser(args.id),
    users: () => getUsers(),
  },
  User: {
    // here we fetch the `extra` field anytime an `User` is requested
    // in real-life I would check if the query is requesting the `extra`
    // field or not, and only fetch the data if requested by the query
    extra: (parent) => {
      return getUserExtra(parent.id)
    },
  }
}

我遇到的问题是 GraphQL 代码生成器生成了一个Resolver期望Query#users返回完整User形状的类型,当然它不知道即使我从 中返回部分形状Query#users,由于User#extra客户端最终会收到尽管如此,预期的形状。

在让 TS 满意的同时处理这种情况的最佳方法是什么?

4

1 回答 1

1

当我遇到这些情况时,我将extra字段设为可为空(替换extra: UserExtra!extra: UserExtra)。有许多关于如何在 Graphql 模式中处理可空性的文章(两个对我有影响)。

据推测,这些extra字段在不同的解析器中是分开的,因为您必须做一些额外的工作来获取它们,比如从另一个服务或数据存储请求数据。如果该请求最终失败,那么架构最好将类型声明为可为空,这样其余的用户数据仍会返回并extra设置为 null,而不是因为为null 和违反架构类型而丢弃其他user数据。extra这篇文章很好地详细解释了这个问题Non-null fields mean small failures have an outsized impact。权衡是,然后您的客户端代码需要检查是否为空,但有人可能会争辩说,这会迫使您的客户端代码考虑更优雅地处理合理的失败案例,这是一件好事。extra

此更改还将解决您尝试解决的原始问题,因为extra将是生成的 graphql-code-generator 类型中的可选类型,并且您的主要用户解析器不需要返回它。

于 2020-10-16T22:12:42.693 回答