所有文档和教程通常都显示简单的突变示例,如下所示:
extend type Mutation {
edit(postId: String): String
}
但是,edit
方法必须在所有实体中都是唯一的,在我看来,这不是一种非常健壮的编写方法。我想描述类似于我们描述查询的突变,类似这样:
type PostMutation {
edit(postId: String): String
}
extend type Mutation {
post: PostMutation
}
这似乎是一个有效的架构(它可以编译,并且可以在生成的graph-i-ql文档中看到它)。但是我找不到让解析器使用此架构的方法。
这是GraphQL支持的情况吗?
答案 0 :(得分:3)
这是可能的,但通常不是一个好主意,因为:
这违反约定。按照约定,突变始终是根源。为了区分对不同类型执行相同操作,您可以命名突变,例如editPost
和editComment
,而不仅仅是edit
。
从概念上讲,从根源上进行突变是有意义的。无论您执行的任何操作(喜欢帖子,验证电子邮件,提交订单等)都不依赖GraphQL在执行操作之前,请先解决其他字段。这与您实际查询数据时不同。例如,要获取帖子的评论,我们可能必须解析每个帖子的user
字段,然后是posts
字段,最后是comments
字段。在每个“级别”,字段的内容取决于父字段解析为的值。突变通常不是这种情况。
在后台,突变被顺序解决。这与并行发生的正常场分辨率相反。这意味着,例如,firstName
类型的lastName
和User
被同时解析。但是,如果您的操作类型为mutation
,则一次将完全解析根字段。因此,在这样的查询中:
mutation SomeOperationName {
createUser
editUser
deleteUser
}
每个突变将一次出现,并按照它们在文档中出现的顺序进行。但是,这仅适用于根目录,并且仅在操作为mutation
时有效,因此这三个字段将并行解析:
mutation SomeOperationName {
user {
create
edit
delete
}
}
尽管有上述规定,如果您仍然想要这样做,这就是使用makeExecutableSchema
时的做法,这是阿波罗在幕后使用的方式:
const resolvers = {
Mutation: {
post: () => ({}), // return an empty object,
},
PostMutation: {
edit: () => editPost(),
},
// Other types here
}
您的架构将PostMutation
定义为对象类型,因此GraphQL希望该字段返回一个对象。如果您省略post
的解析器,它将返回null,这意味着不会触发返回类型(PostMutation
)的解析器。这也意味着,我们还可以编写:
mutation {
post
}
不执行任何操作,但仍然是有效的查询。这是避免这种架构结构的另一个原因。
答案 1 :(得分:3)
完全不同意丹尼尔!
这是一种了不起的方法,可帮助前端程序快速了解哪些操作具有一个或另一个资源/模型。而且不要列出所有的突变列表。
在一个请求中调用多个突变是常见的反模式。对于这种情况,最好创建一个复杂的突变。
但是,即使您需要对多个突变进行此类操作,也可以使用别名:
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',
]);
喜欢/不喜欢的方法与超时异步并按顺序工作