如何在 RESTful API 中表示批量操作
分类:技术
作为 RESTful API 的拥趸,最常被质疑的就是「批量操作很难 RESTful 起来」,似乎找不出对应批量操作的 HTTP 动词来。
早年间看文章,不少解决方案是先创建一个临时资源表示需要批量操作的资源,然后针对这个临时资源进行操作。将批量操作拆分到两个接口,多少有些削足适履的意思。
现在再看,情况就明朗起来了:用 PATCH
方法配合 JSON Patch 就能很好地表示批量操作。
PATCH
方法平时比较少用到,即便使用,一般也是以 JSON Merge Patch 格式更新单个资源的部分字段。例如修改一篇文章的发布时间和标题、删除广告:
PATCH /articles/42 HTTP/1.1
Content-Type: application/merge-patch+json
{
"title": "Oops!",
"published_at": "2019-01-02T03:04:05Z",
"advertisement": null
}
相当于是给出了资源的部分表示,要求合并服务器上的表示与客户端所发送的表示。而 JSON Patch 格式的内容则是针对修改的结构化描述,例如上面的例子就会变成:
PATCH /articles/42 HTTP/1.1
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/title", "value": "Oops!"},
{"op": "replace", "path": "/published_at", "value": "2019-01-02T03:04:05Z"},
{"op": "remove", "path": "/advertisement"}
]
其中 op
表示需要进行的操作,path
则是 JSON Pointer,用来指向 URL 所表示资源中的具体某个对象。数组中的多个操作依次进行。
使用 JSON Patch 来表示对单独资源的修改有些大材小用。不过如果将 JSON Patch 应用于合集资源,就可以很方便地表示所需的批量操作了。例如批量删除 ID 为 42 和 43 的文章,同时将 ID 为 45 的文章设为隐藏,并且新建一篇文章:
PATCH /articles HTTP/1.1
Content-Type: application/json-patch+json
[
{"op": "remove", "path": "/42"},
{"op": "remove", "path": "/43"},
{"op": "replace", "path": "/45/visible", "value": false},
{"op": "add", "path": "/-", "value": {
"title": "Start Wars",
"content": "A long time ago, in a country far, far away..."
}}
]
甚至有些过于批量……
上面例子中,因为 PATCH
操作的 URL 资源是 /articles
,所以 JSON Pointer /42
指向的就是 /articles/42
资源;同理 /45/visible
指向 /articles/45
资源的 visible
字段。而 /-
中的 -
则是 JSON Patch 中用来表示数组末尾的特殊索引。
这样一来,就可以名正言顺地对合集资源做 PATCH
,进行批量操作了 😄