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

GraphQL: Many small mutations, or one bulk mutation?

假设我是一名用户,我正在某个任意应用程序上编辑我的个人资料。该应用程序让我进行了一系列更改,完成后,我单击 "Save" 并更新了我的个人资料。

在 GraphQL 中推荐的最佳实践是什么来处理这样的大型更新?在我看来,有几个选项:

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

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

缺点:这是否违背了 GraphQL 中 "one round trip to the server" 的目的,因为它需要... 5?

B) 许多小的突变,称为服务器端。您可以 post 将数据 blob 发送到服务器并具有解析它的函数,并对它找到的数据运行单独的突变,而不是从客户端调用 5 个突变,需要 5 次往返。

优点:一次往返

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

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

优点:DX;往返一次。

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


我在网上找不到太多关于 "right way" 在 GraphQL 中做这种事情的方法。希望在这里找到一些答案/反馈。谢谢!

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

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

A) Many small mutations. If the user changed 5 things (i.e., name, email, username, image, bio) the client could fire off 5 mutations to the server.

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

这是一个例子:

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

B) Many small mutations, called server-side. Rather than calling 5 mutations from the client, requiring 5 round trips, you could post a data blob to the server and have a function that parses it, and runs individual mutations on the data it finds.

当您更改多个字段或一次执行多个查询时,这正是 GraphQL 为您所做的。

C) One large mutation. The user sends the data blob to the server via a single mutation, which sets the new data in bulk on the document rather than running individual mutations on each field.

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

Cons: Since fields are being passed in as arguments, this open the application to attack. A malicious user could try passing in arbitrary fields, setting fields that shouldn't be changed (i.e. an isAdmin field), etc. The mutation would have to be smart to know which fields are allowed to be updated, and reject / ignore the rest.

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