假设您有一个user
类型,而一个user
有很多posts
。然后想象您想找到一个用户,并删除其所有帖子。一种方法是实现以下mutation
字段:
field deleteAllPosts, types[Types::PostType] do
argument :user_id, types.String
resolve -> (obj,args,ctx){
posts = Posts.where(user_id:args[:user_id])
posts.each{|post| post.destroy}
}
end
然后查询
mutation {
deleteAllPosts(user_id:1)
}
将删除ID为1的用户的所有帖子。
在执行此操作之前,我曾想过要以不同的方式进行此操作,但我从未见过其他人这样做过。我想检查一下这种不同的方式没有任何陷阱,或者是我不应该使用它的原因。
其想法是改为在deletePost
上放置一个PostType
字段,并在突变上放置一个findUser
字段(通常是查询字段)。假设很明显如何定义这些字段,然后我进行查询
mutation{
findUser(id:1){
posts{
deletePost{
id
}
}
}
}
这是个坏主意吗?
根据反馈进行编辑:我担心的一件事是,用户可以原则上可以在内部进行deletePost
选择查询。但是我很想说那是“他们的错”。我想 说“只有在突变查询中才能进行此选择”,但是我认为这在GraphQL中是不可能的。
为了避免XY问题,这就是为什么我热衷于使用这种想法,而不是最初的想法。感觉更具表现力(换句话说,感觉不那么多余)。假设一段时间后,您决定要删除属于特定posts
的那些users
的所有group
。然后在我认为的“惯例”中,您应该创建一个全新的突变字段:
field deleteAllPostsInGroup, types[Types::PostType] do
argument :group_id, types.String
resolve -> (obj,args,ctx){
posts = Group.find_by(args[:group_id]).users.map{|u| u.posts}.flatten
posts.each{|post| post.destroy}
}
end
在我建议的约定中,您仅定义了一个琐碎的findGroup
字段(但您必须在不属于突变的突变中对其进行定义),然后进行查询:
mutation{
findGroup(id:1){
users{
posts{
deletePost{
id
}
}
}
}
}
我想我真正想做的是使用 query 查找一些数据,然后变异我找到的数据< / strong>。我不知道如何在GraphQL中执行此操作。
第二编辑::这个问题似乎有一个明确定义的组成部分,我已经问过here。事实证明,其中一个问题可以回答另一个问题,可以解决,但我不知道该怎么回事。
答案 0 :(得分:0)
这基本上是一个代码质量问题,类似于询问DRY原理或封装的要点。
https://graphql.org/learn/queries/中的一句话是:
在REST中,任何请求都可能最终导致服务器上出现一些副作用,但按照惯例,建议不要使用GET请求来修改数据。 GraphQL是类似的-从技术上讲,任何查询都可以实现以引起数据写入。但是,建立一个约定是很有用的,该约定应使引起写操作的任何操作都应通过突变显式发送。
这是一个很好的约定,因为它使维护,测试和调试更加容易。无论是有意还是无意,副作用都很难追踪和理解。尤其是在GraphQL查询中包含它们时,查询可能会非常大且复杂。没有什么可以阻止您同时查询和修改同一个对象及其同级对象,并通过简单的嵌套在一个查询中多次执行此操作。这很容易弄错。
即使您将它拉开,代码的可读性和可维护性也会受到影响。例如。如果您知道只有您的变异曾经修改过数据,并且查询对它没有影响,那么您将立即知道从哪里开始寻找特定行为的实现。通常来说,您的程序的工作原理也更容易推断。
如果您只编写名称正确的细小突变,那么比起复杂查询在不同点更新不同数据的情况,您可以更轻松地推断出它们的作用。
最后但并非最不重要的一点是,如果您需要将工作转移给其他人,则遵循约定很有用。
简而言之-一切都是为了让自己和他人的生活在未来更加轻松。
编辑
好的,所以我知道您要进行的工作-您希望为变异提供GraphQL查询的灵活性。当然,这个特定的例子会起作用。不采用这种方式只会导致未来。如果deletePost
是您将要定义的唯一操作,则没有必要讨论。
如果不是这种情况,那么如果要删除5条特定的用户帖子怎么办?您是否会为findGroup
提供额外的参数,然后将其传递给树?但是,为什么findGroup
方法必须知道您将如何处理其结果?这种违背了灵活查询本身的想法。如果您还想对用户执行变异该怎么办? findGroup的更多参数?如果可以通过其他方式查询用户和帖子,例如按域划分的用户,按类别分类的帖子等,该怎么办?在那里也定义相同的参数吗?您如何确保每次操作(尤其是一次执行几个操作)时,所有关系链接都已正确删除到数据库中?您将必须想象查询和查询突变的每种可能组合,并为它们适当地编写代码。由于查询大小不受限制,因此最终可能很难做到。即使单个查询突变(deletePost
)的目的很明确且易于掌握,但整个 query 都不是。很快,即使对于您来说,您的查询也会变得太复杂以至于无法理解,您可能会开始将其分解为较小的查询,这只会进行特定的突变。这样,您就可以回到原始约定,但是要返回一个更复杂的版本。您可能最终也会定义一些常规突变。您将如何更新或添加帖子?那将使您的逻辑无处不在。
如果您正在编写突变,则不会出现这些问题。为了获得更好的可维护性,需要做更多的工作。
这些都是将来的潜在问题(可能还有更多)。如果这些与您无关,请继续执行。我个人会避免这样做的一个项目,但是如果您真的很聪明,我看不到任何技术上会完全阻止您实现所需目标的东西:]