我的 Apollo GraphQL 解析器如何才能 'lookahead' 到 children 而不会失去传统解析器结构的优势?

How can my Apollo GraphQL resolver 'lookahead' to children without losing the benefits of a traditional resolver structure?

我正在开发位于 REST 服务前面的 GraphQL API。这个 REST 服务是一个具有许多复杂参数的单一端点——我们没有将所有参数放在一个单一的 GraphQL 字段上,而是在逻辑上将其分解为一棵 GraphQL 字段和类型树。

特别是这棵树的底部有点动态和无界。总之,它看起来像这个简化的模式:

type Query {
  outer: OuterWrapper!
}

type OuterWrapper {
  inner: InnerWrapper!
}

type InnerWrapper {
  recurse(name: String = ""): RecursiveType!
}

type RecursiveType {
  recurse(name: String = ""): [RecursiveType!]!
  name: String!
}

目前,我们只有一个 Apollo 解析器位于树的顶部 (outer),并使用 graphql-fields library to process the info parameter. Essentially, we're 'looking ahead' to the children - a pattern to optimise 后端查询。

这对我们来说非常有效 - 我们将 child 字段和参数映射到单个 REST 请求中,然后将响应映射回正确的结构。

但是,它确实有两个限制:

  1. graphql-fields 响应不包括默认参数值。如果我编写了一个合适的 recurse 解析器,Apollo 将传入 name 的模式默认值(如果它不在查询中)。我找到了一个我要切换到的替代库 (graphql-parse-resolve-info),但这不是 Apollo 解决方案,并且...
  2. 如果我们抛出一个错误,该路径反映它发生在 outer 解析器中,而不是在更准确、对用户有用的树的更下方。

总的来说,我担心我会继续发现使用这种结构不太有效的东西,我正在考虑如何摆脱它。

有没有一种方法可以使用 traditional/fully 指定的解析器结构逐步构建我的单一后端 REST 请求?

我可以想象解析器构建查询,并将其存储在 context 中 - outer 解析器将创建查询,后续解析器将根据他们认为合适的方式更改它。然后每个解析器可以 return 一个等待 REST 响应的承诺。但是,我看不到一个好方法来知道何时调用了我的所有解析器(并进行了更改),从而将 REST 请求发送到后端,或者让每个解析器知道它在查询结构中的位置(以及因此在 REST 响应中查找数据的位置)。

还有没有我没有考虑过的方法?

GraphQL 的 top-down way of executing requests 并不真正适合解析器构建一个一旦所有解析器都是 运行 就会执行的查询。部分原因是,父字段的解析器必须在调用任何子字段解析器之前完成执行。毕竟,它们需要用父解析到的值来调用。

如果您对数据源进行了多次调用,则将它们拆分到不同的解析器可能是有意义的。但是,如果您只需要对数据源进行一次调用,那么在顶层执行此操作并使用 "lookahead" 是最好的方法。 graphql-parse-resolve-info 是一个很好的图书馆,可以帮助解决这个问题。

与您现在所做的相比,唯一的改进可能是将 t运行s 形成 REST 响应的大部分逻辑移动到某些非根字段的解析器中。通过这种方式,随着执行遍历查询的每个 "level",您可以逐渐 t运行 形成传递给每个解析器的 parent 值。