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

Are mutation methods required to be on the top level?

所有文档和教程通常都会展示像这样的简单突变示例:

extend type Mutation {
  edit(postId: String): String
}

但是这样 edit 方法必须在所有实体中都是唯一的,在我看来,这似乎不是一种非常可靠的编写方式。我想描述类似于我们描述查询的方式的突变,像这样:

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

extend type Mutation {
  post: PostMutation
}

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

GraphQL 支持这种情况吗?

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

它违反了规范。 来自 section 6.3.1:

Because the resolution of fields other than top‐level mutation fields must always be side effect‐free and idempotent, the execution order must not affect the result, and hence the server has the freedom to execute the field entries in whatever order it deems optimal.

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

从概念上讲,在根部进行突变是有意义的。无论您在做什么(点赞 post、验证电子邮件、提交订单等。 ) 不依赖于 GraphQL 在采取行动之前必须解析额外的字段。这与您实际查询数据时不同。例如,要获得对 post 的评论,我们可能必须解析 user 字段,然后是 posts 字段,最后是每个 [=56] 的 comments 字段=].在每个 "level",字段的内容取决于父字段解析为的值。突变通常不是这种情况。

在底层,突变是按顺序解决的。这与并行发生的正常场分辨率相反。这意味着,例如,User 类型的 firstNamelastName 会同时解析。但是,如果您的操作类型是 mutation,根字段将一次解析一个。所以在这样的查询中:

mutation SomeOperationName {
  createUser
  editUser
  deleteUser
}

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

mutation SomeOperationName {
  user {
    create
    edit
    delete
  }
}

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

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

您的架构将 PostMutation 定义为对象类型,因此 GraphQL 期望该字段 return 是一个对象。如果您省略 post 的解析器,它将 return 为空,这意味着 returning 类型 (PostMutation) 的 none 解析器将被触发.这也意味着,我们也可以这样写:

mutation {
  post
}

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

绝对不同意大牛的观点!

这是一种了不起的方法,可以帮助前端快速了解哪些操作有一个或另一个 resource/model。并且不要列出冗长的突变列表。

在一个请求中调用多个变更是常见的反模式。对于这种情况,最好创建一个复杂的突变。

但即使您需要对多个突变进行此类操作,您也可以使用别名:

await graphql({
  schema,
  source: `
  mutation {
    op1: article { like(id: 1) }
    op2: article { like(id: 2) }
    op3: article { unlike(id: 3) }
    op4: article { like(id: 4) }
  }
`,
});

expect(serialResults).toEqual([
  'like 1 executed with timeout 100ms',
  'like 2 executed with timeout 100ms',
  'unlike 3 executed with timeout 5ms',
  'like 4 executed with timeout 100ms',
]);

查看以下测试用例:https://github.com/nodkz/conf-talks/blob/master/articles/graphql/schema-design/tests/mutations-test.js

方法like/unlike与超时异步并按顺序工作