首页 文章

通过字段定义GraphQL中的突变:这是不好的做法吗?

提问于
浏览
1

假设你有一个 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的用户的所有帖子 .

在我这样做之前,我想过以不同的方式做这件事,我有任何陷阱,或者我不应该使用它的原因 .

我们的想法是为 PostType 设置 deletePost 字段,在变异上设置 findUser 字段(通常是查询字段) . 假设显然如何定义这些字段,我将进行查询

mutation{
  findUser(id:1){
    posts{
      deletePost{
      id
      }
    }
  }
}

这是一个坏主意吗?

Edit in response to feedback :我关注的一件事是,用户原则上可以在查询中进行 deletePost 选择 . 但我'm tempted to say that that' s "their fault" . 我想说"this selection can only be made if it is inside of a mutation query",但我不想在GraphQL中使用't think that' .

为了避免XY问题,这就是为什么我热衷于使用这个想法而不是最初的想法 . 感觉更具表现力(换句话说,感觉不那么多余) . 假设在一段时间后,您决定要删除属于特定 group 的那些 users 的所有 posts . 那么在我认为的'convention'中,你应该创建一个全新的变异字段:

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
        }
      }
    }
  }
}

我想我真正想做的是使用查询 find 一些数据,然后 mutate the data I've found . 我不知道如何在GraphQL中执行此操作 .

Second Edit: 好像这个问题中有一个明确定义的组成部分,我已经问过here . 事实证明,这些问题中的一个能够回答另一个问题,并且可能会被关闭,但我还不知道哪个方向 .

1 回答

  • 0

    这基本上是代码质量问题,类似于询问DRY原则或封装的要点 .

    来自https://graphql.org/learn/queries/的引用如下:

    在REST中,任何请求都可能最终导致服务器上出现一些副作用,但按照惯例,建议不要使用GET请求来修改数据 . GraphQL类似 - 从技术上讲,任何查询都可以实现以引起数据写入 . 但是, Build 一个约定是有用的,任何导致写入的操作都应该通过突变显式发送 .

    这是一个很好的约定,因为它使维护,测试和调试更容易 . 副作用,无论是有意还是无意,都可能非常难以追踪和理解 . 特别是如果你在GraphQL查询中有它们,它们可以是任意大而复杂的 . 没有什么可以阻止您同时查询和修改同一个对象及其兄弟姐妹,并通过简单的嵌套在一个查询中多次执行此操作 . 这很容易弄错 .

    即使你把它拉下来,代码的可读性和可维护性也会受到影响 . 例如 . 如果您知道只有您的突变修改了数据,并且查询对它没有影响,您将立即知道从哪里开始寻找特定行为的实现 . 关于你的程序如何正常工作也更容易理由 .

    如果您只编写小的,正确命名的粒度突变,那么如果您有一个在不同点更新不同数据的复杂查询,您可以更容易地推断它们的作用 .

    最后但并非最不重要的是,如果您需要将工作转移给其他人,那么遵守惯例会非常有用 .

    简而言之 - 所有这一切都是为了让未来的生活更轻松 .


    EDIT

    好的,所以我看到你要去的地方 - 你想给突变提供GraphQL查询的灵活性 . 当然,这个特殊的例子可行 . 不走这条路只会是 future . 如果 deletePost 是您将要定义的唯一操作,那么讨论这一点毫无意义 .

    如果's not the case, then what if you wanted to delete, let'说,5个特定的用户帖子?你会给 findGroup 提供额外的参数然后将它们传递给树吗?但那么为什么 findGroup 方法必须知道你将如何处理它的结果呢?这种做法违背了灵活查询本身的想法 . 如果您还想对用户执行突变怎么办? findGroup的更多参数?如果可以通过不同的方式查询用户和帖子,例如按域分类的用户,按类别分类的帖子等,该怎么办?那里也定义相同的参数?您如何确保每次操作(特别是如果您同时执行其中一些操作),所有关系链接都会在您的数据库中正确删除?您必须想象查询和查询突变的每种可能组合以及适当的代码 . 由于查询大小无限制,最终可能很难做到 . 即使单个查询 - 突变( deletePost )的目的是明确的,也是如此容易掌握,整体查询不会 . 很快你的查询就变得太复杂了,即使对你和你来说也很难理解'd probably begin breaking them down to smaller ones, which would only do specific mutations. This way you' d回到最初的惯例,但它是一个更复杂的版本 . 您可能最终也会定义一些常规突变 . 你会如何更新或添加帖子,例如?这会在整个地方传播你的逻辑 .

    如果您正在编写突变,则不会出现这些问题 . 为了更好的可维护性,这需要更多的工作 .

    这些都是未来的问题(可能还有更多) . 如果这些都没有看到任何在技术上完全阻止你实现你想要的东西:]

相关问题