REST批量删除多个项目

REST delete multiple items in the batch

我需要在批处理中按 ID 删除多个项目,但是 HTTP DELETE 不支持正文负载。

变通选项:

1. @DELETE /path/abc?itemId=1&itemId=2&itemId=3 on the server side it will be parsed as List of ids and DELETE operation will be performed on each item.

2. @POST /path/abc including JSON payload containing all ids. { ids: [1, 2, 3] }

这有多糟糕,哪个选项更可取?还有其他选择吗?

更新:请注意性能是这里的关键,它不是对每个单独的id执行删除操作的选项。

这些年来,很多人对此产生了疑问,我们可以在旁边的相关问题中看到。似乎接受的答案范围从“肯定会这样做”到“它明显滥用协议”。由于多年前提出了很多问题,让我们深入研究 2014 年 6 月 (RFC 7231) 的 HTTP 1.1 规范,以便更好地了解明确不鼓励的内容。

第一个建议的解决方法:

首先,关于 Section 2 上的资源和 URI 本身:

The target of an HTTP request is called a "resource". HTTP does not limit the nature of a resource; it merely defines an interface that might be used to interact with resources. Each resource is identified by a Uniform Resource Identifier (URI).

基于此,有些人可能会争辩说,由于 HTTP 不限制资源的性质,因此包含多个 id 的 URI 是可能的。我个人认为这是一个解释问题。

关于您提出的第一个解决方法 (DELETE '/path/abc?itemId=1&itemId=2&itemId=3'),我们可以得出结论,如果您将资源视为实体集合中的单个文档,这是令人气馁的,而如果您将资源视为实体集合本身。

第二个建议的解决方法:

关于您提出的第二个解决方法 (POST '/path/abc' with body: { ids: [1, 2, 3] }),使用 POST 删除方法可能会产生误导。 Section 4.3.3 部分说的是 POST:

The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others): Providing a block of data, such as the fields entered into an HTML form, to a data-handling process; Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles; Creating a new resource that has yet to be identified by the origin server; and Appending data to a resource's existing representation(s).

虽然有一些 space 用于解释 POST 的“其他”功能,但它显然与我们拥有用于资源移除的方法 DELETE 的事实相冲突,因为我们可以在 Section 4.1:

中看到

The DELETE method removes all current representations of the target resource.

所以我个人强烈反对使用POST来删除资源。

另一种解决方法:

受您第二个解决方法的启发,我们建议再使用一个:

DELETE '/path/abc' with body: { ids: [1, 2, 3] }

它与解决方法二中提出的几乎相同,只是使用正确的 HTTP 方法进行删除。在这里,我们对在 DELETE 请求中使用实体 body 感到困惑。有很多人说它无效,但让我们坚持规范的 Section 4.3.5

A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.

因此,我们可以得出结论,规范不会阻止 DELETE 拥有 body 有效载荷。不幸的是,一些现有的实现可能会拒绝请求...但这对我们今天有何影响?

很难 100% 确定,但是使用 fetch 提出的现代请求不允许 GETHEADbody。这就是项目 34 上的 Fetch Standard states at Section 5.3

If either body exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.

我们可以确认 fetch pollyfill at line 342.

的实施方式相同

最后的想法:

由于 HTTP 规范允许使用 DELETEbody 有效负载的替代解决方法可行,并且所有具有 fetch 的现代浏览器都支持该方法,并且自 IE10 开始使用 polyfill,我推荐这种方式来以有效且完整的方式进行批量删除。

请务必了解 HTTP 方法在 "transferring documents across a network" 的域中运行,而不是在您自己的自定义域中运行。

你的资源模型不是你的领域模型也不是你的数据模型。

替代拼写:REST API 是使您的域看起来像网站的外观

在外观背后,实现可以为所欲为,但要考虑到如果实现不符合消息描述的语义,那么它(而不是客户端)要对造成的任何损害负责由差异。

DELETE /path/abc?itemId=1&itemId=2&itemId=3

因此该 HTTP 请求明确表示 "Apply the delete semantics to the document described by /path/abc?itemId=1&itemId=2&itemId=3"。事实上,这个文档是耐用品商店中三个不同项目的组合,每个项目都需要单独删除,这是一个实现细节。 REST 的 的一部分是客户端与这类知识完全隔离。

但是,我觉得这是很多人迷路的地方,对该删除请求的响应返回的元数据告诉客户端没有关于具有不同标识符的资源。

就客户端而言,/path/abc 是不同于 /path/abc?itemId=1&itemId=2&itemId=3 的标识符。因此,如果客户端执行 /path/abc 的 GET,并收到包含 itemIds 1、2、3 的表示;然后提交您描述的删除,删除成功后,它仍然会在自己的缓存中包含包含 /path/abc 的表示。

这可能是您想要的,也可能不是。如果您正在使用 REST(通过 HTTP),这是您在设计中应该考虑的事情。

POST /path/abc

some-useful-payload

此方法告诉客户端我们正在对 /path/abc 进行一些(可能不安全的)更改,如果成功则需要使之前的表示无效。客户端应重复其早先的 GET /path/abc 请求以刷新其先前的表示,而不是使用任何早先的无效副本。

但和以前一样,它不会影响其他资源的缓存副本

/path/abc/1
/path/abc/2
/path/abc/3

所有这些仍将保留在缓存中,即使它们已经 "deleted"。

公平地说,很多人并不关心,因为他们没有考虑客户端缓存他们从网络服务器获得的数据。并且您可以将元数据添加到 Web 服务器发送的响应中,以告知客户端(和中间组件)表示不支持缓存,或者可以缓存结果但必须在每次使用时重新验证。

再说一遍:你的资源模型不是你的域模型也不是你的数据模型。 REST API 是一种思考正在发生的事情的不同方式,并且 REST 架构风格经过调整以解决特定问题,因此可能不适合您试图解决的更简单的问题。

That doesn’t mean that I think everyone should design their own systems according to the REST architectural style. REST is intended for long-lived network-based applications that span multiple organizations. If you don’t see a need for the constraints, then don’t use them. That’s fine with me as long as you don’t call the result a REST API. I have no problem with systems that are true to their own architectural style. -- Fielding, 2008