GraphQL:许多小的突变,还是一个大的突变?

Posted

技术标签:

【中文标题】GraphQL:许多小的突变,还是一个大的突变?【英文标题】:GraphQL: Many small mutations, or one bulk mutation? 【发布时间】:2017-10-28 01:17:21 【问题描述】:

假设我是一名用户,我正在某个任意应用程序上编辑我的个人资料。该应用程序让我进行了一系列更改,完成后,我点击“保存”,我的个人资料就会更新。

在 GraphQL 中处理此类大型更新的推荐最佳做法是什么?在我看来,有几个选择:

A) 许多小的突变。如果用户更改了 5 项内容(即姓名、电子邮件、用户名、图像、简历),则客户端可以向服务器触发 5 次更改。

优点:更小、更孤立的操作。

缺点:这不是违背了 GraphQL 中“往返服务器”的目的,因为它需要... 5?

B) 许多小的突变,称为服务器端。与其从客户端调用 5 个变更(需要 5 次往返),不如将一个数据 blob 发布到服务器并拥有一个解析它的函数,并对它找到的数据运行单个变更。

优点:往返一次

缺点:我们必须在应用程序中添加另一个层来处理这个问题。随着时间的推移,新功能会变得混乱、难以测试且难以维护。

C) 一个大突变。用户通过单个突变将数据 blob 发送到服务器,这会将新数据批量设置在文档上,而不是在每个字段上运行单独的突变。

优点:DX;往返一次。

缺点:由于字段是作为参数传入的,这会使应用程序受到攻击。恶意用户可以尝试传入任意字段,设置不应更改的字段(即isAdmin 字段)等。突变必须聪明地知道允许更新哪些字段,并拒绝/忽略其余的。


我在网上找不到太多关于哪种方式是在 GraphQL 中做这种事情的“正确方式”。希望在这里找到一些答案/反馈。谢谢!

【问题讨论】:

往返服务器的真正目的是查询,而不是突变。 我认为你想多了。方法 1 和 3 都是解决此问题的正确方法,具体取决于您的需要。我会选择 3,这在大多数情况下可能是最稳健的方式。 【参考方案1】:

A) 许多小的突变。如果用户更改了 5 项内容(即姓名、电子邮件、用户名、图像、简历),则客户端可以向服务器触发 5 次更改。

您可以在一个请求中执行多个变更。无需多次调用服务器。

这是一个例子:

mutation 
  setUserName(name: "new_name")  ok 
  setUserEmail(email: "new_email")  ok 

B) 许多小的突变,称为服务器端。与其从客户端调用 5 个变更(需要 5 次往返),不如将一个数据 blob 发布到服务器并拥有一个解析它的函数,并对它找到的数据运行单个变更。

这正是 GraphQL 在您更改多个字段或一次执行多个查询时为您做的事情。

C) 一个大突变。用户通过单个突变将数据 blob 发送到服务器,该突变将新数据批量设置在文档上,而不是在每个字段上运行单独的突变。

即使您使用多个字段,您仍然可以批量设置数据。 这将要求您将请求传递给中间件,而不是直接更新数据库,该中间件将在执行所有突变解析器后构建并执行单个查询。

缺点:由于字段是作为参数传入的,这会使应用程序受到攻击。恶意用户可以尝试传入任意字段,设置不应更改的字段(即 isAdmin 字段)等。突变必须聪明地知道允许更新哪些字段,并拒绝/忽略其余字段.

您不应使用任意变量,而应将所有允许的属性作为参数列出。

【讨论】:

【参考方案2】:

我会选择第三种解决方案,一个大突变。我不确定我是否理解您关于恶意用户传递任意字段的观点:他们将无法传递未在您的架构中定义的字段。

至于服务器端逻辑,无论如何您都必须进行智能检查:您永远不能信任客户端!

【讨论】:

谢谢!我肯定是在考虑它的安全方面。我没有意识到您不能将任意值传递给突变来尝试欺骗它,您只能提供架构中指定的确切字段,并且它们必须是预期的类型。因此,这意味着您可以从单个突变中获得的工作越多越好。这是更大、更通用的突变!

以上是关于GraphQL:许多小的突变,还是一个大的突变?的主要内容,如果未能解决你的问题,请参考以下文章

我必须在带有 Sequelize 的 GraphQL 突变中返回啥?

在 Graphcool / GraphQL 中发布更新突变时如何“更新”数组/嵌套字段?

Vuex 状态随突变而变化 - apollo graphql 查询

GraphQL 突变“在将标头发送到客户端后无法设置标头”

从另一个突变中调用 GraphQL 突变?

GraphQL - 如何在查询多个突变期间检索先前突变的 id