突变方法是否需要在顶层?

tim*_*der 4 apollo graphql apollo-server

所有文档和教程通常都会显示如下所示的简单突变示例:

extend type Mutation {
  edit(postId: String): String
}
Run Code Online (Sandbox Code Playgroud)

但是这种edit方法必须在所有实体中都是唯一的,在我看来,这似乎不是一种非常健壮的写东西方式。我想描述与我们描述查询类似的突变,如下所示:

type PostMutation {
  edit(postId: String): String
}

extend type Mutation {
  post: PostMutation
}
Run Code Online (Sandbox Code Playgroud)

这似乎是一个有效的模式(它可以编译,我可以看到它反映在生成的 graph-i-ql 文档中)。但是我找不到让解析器使用此架构的方法。

这是 GraphQL 支持的案例吗?

Dan*_*den 5

这是可能的,但通常不是一个好主意,因为:

它打破了规范。第 6.3.1 节

因为除顶级突变字段之外的字段的解析必须始终是无副作用和幂等的,执行顺序不能影响结果,因此服务器可以自由地以它认为最佳的任何顺序执行字段条目。

换句话说,只有变异根类型上的字段应该有像 CRUD 操作这样的副作用。

在根上进行突变在概念上是有意义的。无论您在做什么(喜欢帖子、验证电子邮件、提交订单等),都不依赖于 GraphQL 在采取行动之前必须解析其他字段。这与您实际查询数据时不同。例如,要获得对帖子的评论,我们可能必须解析一个user字段,然后是一个posts字段,最后是comments每个帖子的字段。在每个“级别”,字段的内容取决于父字段解析为的值。这通常不是突变的情况。

在幕后,突变是按顺序解决的。这与并行发生的正常场分辨率相反。这意味着,例如,同时解析一个类型的firstName和。但是,如果您的操作类型是,则一次解析所有根字段。所以在这样的查询中:lastNameUsermutation

mutation SomeOperationName {
  createUser
  editUser
  deleteUser
}
Run Code Online (Sandbox Code Playgroud)

每个突变将一次发生一个,按照它们在文档中出现的顺序。但是,这仅适用于根并且仅当操作为 a 时mutation,因此这三个字段将并行解析:

mutation SomeOperationName {
  user {
    create
    edit
    delete
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您仍然想这样做,尽管有上述情况,这就是您在使用 时的做法makeExecutableSchema,这就是 Apollo 在幕后使用的方法:

const resolvers = {
  Mutation: {
    post: () => ({}), // return an empty object,
  },
  PostMutation: {
    edit: () => editPost(),
  },
  // Other types here
}
Run Code Online (Sandbox Code Playgroud)

您的架构定义PostMutation为对象类型,因此 GraphQL 期望该字段返回一个对象。如果省略 for 的解析器post,它将返回 null,这意味着不会PostMutation触发返回类型 ( )的解析器。这也意味着,我们也可以这样写:

mutation {
  post
}
Run Code Online (Sandbox Code Playgroud)

它什么都不做,但仍然是一个有效的查询。这是避免这种模式结构的另一个原因。