Go JSON patch

在这篇文章中,我会向你介绍 json patch,并展示如何在 Go 中使用 json patch 来完成资源的更新操作。

什么是 JSON Patches?

JSON Patch 是一种格式化的方式,用于对 JSON 文件进行部分修改。它定义了一组操作符,可以用来描述如何修改一个 JSON 值。这种方式非常适合在客户端和服务器之间传递部分修改,而不需要传输整个 JSON 文档,从而节省了带宽。

JSON Patch 的规范由 RFC6902 定义,它描述了如下几种操作符:

  • add: 在指定位置添加一个值
  • remove: 移除指定位置的值
  • replace: 用新值替换指定位置的值
  • move: 将指定位置的值移动到另一个位置
  • copy: 将指定位置的值复制到另一个位置
  • test: 测试指定位置的值是否与给定值相等

每个操作符都包含一个路径字符串,用于定位要修改的 JSON 值。路径语法类似于 XPath,使用 / 来分隔各个层级,并使用 0、1、2 等数字来指定数组元素的位置。

为什么需要 JSON Patch?

在现代 Web 应用中,客户端和服务器之间通常需要频繁地交换 JSON 数据。如果每次都需要传输整个 JSON 对象,会造成不必要的带宽浪费,降低应用的响应速度。

JSON Patch 的出现就是为了解决这个问题。它允许我们只传输 JSON 对象的变化部分,而不是整个对象。这不仅可以减少网络传输的数据量,还可以降低服务器的计算负载,因为服务器只需要对变化的部分进行处理,而不需要重新构建整个 JSON 对象。

下面是一些 JSON Patch 的典型应用场景:

  1. 实时协作编辑

在协作编辑应用中,多个用户同时编辑同一份文档。每次有用户进行修改时,服务器只需要将该修改以 JSON Patch 的形式广播给其他用户,而不需要传输整个文档。这可以大大减少网络流量,提高实时协作的响应速度。

  1. 数据同步

在分布式系统中,不同节点之间需要频繁地同步数据。使用 JSON Patch,节点之间只需要交换数据的变化部分,而不是整个数据快照,这可以减少大量的网络开销。

  1. 局部 UI 更新

在现代 Web 应用中,UI 通常由 JSON 数据驱动。当数据发生变化时,我们只需要用 JSON Patch 描述变化部分,然后在客户端应用这些变化,就可以高效地更新 UI,而不需要重新渲染整个视图。

  1. 版本控制

JSON Patch 可以用于记录 JSON 数据的变更历史,从而实现类似于文件版本控制系统的功能。每次变更都可以用一个 JSON Patch 表示,应用所有的 Patch 就可以重建数据的任何历史版本。

除了之前提到的场景之外,JSON Patch 还有一个非常重要的使用场景,那就是作为 HTTP PATCH 方法的请求体,用于对指定的资源进行部分修改。

HTTP 协议中定义了多种方法,例如 GET、POST、PUT、DELETE 等。其中 PATCH 方法是用于对已存在的资源进行部分修改。与 PUT 方法不同,PUT 是完整替换资源,而 PATCH 只更新资源的一部分字段。

PATCH 方法的请求体可以使用多种格式, JSON Patch 就是其中一种流行的格式。它提供了一种标准的、结构化的方式来表示对 JSON 资源的修改操作, 非常适合作为 PATCH 请求的载体。

在 Go 中实现 JSON Patches

Go 标准库中没有直接实现 JSON Patch 的功能,但是我们可以使用第三方库来实现。一个流行的 JSON Patch 库是 evanphx/json-patch

首先,我们需要添加依赖,并导入:

1
go get -u github.com/evanphx/json-patch/v5
1
2
import jsonpatch "github.com/evanphx/json-patch/v5"

然后,我们可以定义一个 JSON 文档:

1
2
3
4
5
6
originalJSON := []byte(`{
"name": "John",
"age": 30,
"skills": ["Go", "Java"]
}`)

接下来,我们创建一个 JSON Patch 文档,描述要对原始 JSON 文档进行的修改操作:

1
2
3
4
5
6
patchJSON := []byte(`[
{"op": "replace", "path": "/name", "value": "Jane"},
{"op": "remove", "path": "/age"},
{"op": "add", "path": "/skills/2", "value": "Python"}
]`)

这个 Patch 将会执行以下操作:

  1. name 字段的值替换为 “Jane”
  2. 删除 age 字段
  3. skills 数组中添加一个新的元素 “Python”

最后,我们应用这个 Patch 并打印修改后的 JSON 文档:

1
2
3
4
5
6
7
8
9
10
11
patch, err := jsonpatch.DecodePatch(patchJSON)
if err != nil {
panic(err)
}

modified, err := patch.Apply(original)
if err != nil {
panic(err)
}
fmt.Printf("Modified document: %s\n", modified)

输出结果将是:

1
2
3
4
5
6
7
8
9
{
"name": "Jane",
"skills": [
"Go",
"Java",
"Python"
]
}

就是这样!通过使用 evanphx/json-patch 库,我们可以在 Go 中方便地实现 RFC6902 JSON Patches 功能。这个库还提供了其他一些高级特性,如应用多个 Patch、从文件中读取 Patch 等。有了这个功能,我们就可以在客户端和服务器之间高效地传递部分 JSON 修改,而不需要传输整个文档。

希望这篇博客对你有所帮助!如果你有任何疑问或反馈,欢迎随时告诉我。


Go JSON patch
https://blog.zhangliangliang.cc/post/go-json-patch.html
作者
Bobby Zhang
发布于
2024年3月5日
许可协议