【问题标题】:Shall I create resolver for each query or for all of its fields in GraphQL?我应该为每个查询或 GraphQL 中的所有字段创建解析器吗?
【发布时间】:2026-01-21 16:25:01
【问题描述】:

我对使用 GraphQL 很感兴趣,并且刚刚开始尝试使用它。

在 GraphQL tutorial 中,可以看到以下引用:

GraphQL 架构中的每个字段都由解析器支持。

但是,如果您查看 gqlgen(这是一个用于构建 GraphQL 服务器的 golang 库)todo example,它使用以下架构:

...
type MyQuery {
    todo(id: ID!): Todo
    lastTodo: Todo
    todos: [Todo!]!
}

type MyMutation {
    createTodo(todo: TodoInput!): Todo!
    updateTodo(id: ID!, changes: Map!): Todo
}

type Todo {
    id: ID!
    text: String!
    done: Boolean!
}
...

它实际上使用了 3 个自动生成的解析器(即,每个 查询 有 1 个,而不是一个字段):

func (r *QueryResolver) Todo(ctx context.Context, id int) (*Todo, error) {
func (r *QueryResolver) LastTodo(ctx context.Context) (*Todo, error) {
func (r *QueryResolver) Todos(ctx context.Context) ([]*Todo, error) {

不为每个字段(而是为每个查询)自动生成解析器是预期的行为吗?

【问题讨论】:

  • 这看起来像MyQuery 类型中的每个字段都有一个解析器,它恰好是*查询类型(但除此之外是普通的 GraphQL 对象类型)。

标签: go graphql


【解决方案1】:

当整个类型由解析器支持时,每个字段都由解析器支持;)

与 SQL 相比 - 当您想要整个记录/行时,通常不会单独询问每个(单个)字段。

当类型解析器不返回所有必需(通过查询)字段的数据时,需要字段级解析器 - f.e.关系。

【讨论】:

  • 我会对任何编程语言的示例感到满意(希望查看具有关系和必填字段的类型)。顺便说一句,如果我在 2 种类型之间创建关系是正确的:即 todo 包含 task 那么我希望一个单独的自动生成的任务解析器?
  • 在你正在使用的库中...... gqlgen - 你有 friends - 与单独解析器的关系字段
  • gqlgen 中的 2 个解析器是如何工作的?即,如果有users.friends 字段和allUsers 查询,users_resolver 将初始化除.friends 之外的所有字段,然后friends 将由其解析器单独解析?由于allUsers 返回[Users] 并且我们无法初始化users.friends 字段,因此我并没有真正了解工作流程。
  • 'engine' 尝试为所有字段收集所需的数据 - 每个对象 (User) 使用额外的解析器,并且每个字段/属性(在开始时未定义)未由类型解析器解析(在每个级别,自上而下)- 为未解析的字段返回 null(无字段解析器、无匹配数据等)