REST风格取消删除

支持数据服务的反删除或延迟/批处理删除是相当常见的要求。 我想知道的是如何以一种RESTful的方式来实现这一点。 我在几个不同的select之间撕裂(其中没有一个对我来说似乎非常有吸引力)。 我相信,在这些不同的选项中,通常需要一个API,它将所有标记为已删除的资源都返回给特定的资源types。

这里有一些我曾经考虑的选项和一些优点/缺点:

将资源标记为已删除的选项:

  • 使用HTTP DELETE将资源标记为已删除。
  • 使用HTTP PUT / POST来更新已删除的标志。 这不正确,因为它将本质上是从HTTP DELETE方法中删除的内容映射到其他HTTP方法。

GET-ing资源标记为删除时的选项:

  • 为标记为已删除的资源返回HTTP状态404。 清洁和透明,但我们如何区分真正被删除的资源和被标记为已删除的资源之间的区别。
  • 返回HTTP状态410.提供方式来区分不同的情况,但是技术上来说410“被认为是永久性的。具有链接编辑能力的客户端应该在用户批准后删除对Request-URI的引用。 在这里“预计”和“应该”可能有足够的摆动空间。 不知道在客户端支持/理解410。
  • 返回HTTP状态200并且包括标志字段指示资源被删除。 这看起来很奇怪,因为首先删除它的想法是因为你真的希望它不出现。 这将过滤掉已删除资源的责任推到了客户端。

包含此已删除资源的回复选项:

  • 省略被删除的资源。 干净简单。 但是如果你真的想知道被删除的资源呢?
  • 将它们与字段一起包括在内,表示它们已被删除。 这将过滤掉已删除资源的责任推到了客户端。 如果您只想通过活动或已删除的资源进行分页,分页会变得非常棘手。

更新标记为删除的资源时的选项:

  • 使用HTTP状态404.资源是否正确? 但是,怎样才能区分标记为已删除的资源和实际删除的资源。 404响应中的HTTP主体可能会在这里消除歧义,但是客户端仍然会parsing/解释你的身体以消除歧义。 也许响应标题可能有帮助吗? 哪一个? 自定义标题?
  • 使用HTTP状态409以及有关资源如何首先被取消删除的消息。

取消删除标记为删除的资源的选项:

  • 使用HTTP PUT / POST进行资源更新操作,并将其标记为活动状态。 只有当您没有为资源的GET操作返回一个HTTP 404时,它才会起作用,因为它不会因为PUT / POST而导致资源“找不到”(404)。
  • 使用HTTP PUT / POST进行资源的创build操作。 这里的问题是哪些数据优先? 在创build操作中发送的数据? 或者正在取消删除的数据? 将其从任何其他将返回的查询中筛选出来。 然后,如果资源标识符指向标记为已删除的资源,则将创build资源的HTTP PUT / POST视为取消删除。
  • 单独的RESTpath专用于取消删除标记为删除的资源。

这绝不是一个详尽的清单。 我只想列举一些在我脑海中弹跳的选项。

我知道如何做到的答案就像往常一样,“取决于”。 我很好奇的是你会用什么资格/要求来做出决定? 你是如何看到这个自己实现或实现的?

按照这本书: RFC 2616-9.7 :

The DELETE method requests that the origin server delete the resource identified by the Request-URI. This method MAY be overridden by human intervention (or other means) on the origin server. The client cannot be guaranteed that the operation has been carried out, even if the status code returned from the origin server indicates that the action has been completed successfully. However, the server SHOULD NOT indicate success unless, at the time the response is given, if it intends to delete the resource or move it to an inaccessible location. 

当你删除一个资源时,服务器应该把资源标记为删除。 它并不是真的要删除资源,它只是不能保证已经进行了操作。 即使如此,服务器不应该说,它没有被删除。

  A successful response SHOULD be 200 (OK) if the response includes an entity describing the status, 202 (Accepted) if the action has not yet been enacted, or 204 (No Content) if the action has been enacted but the response does not include an entity. 

如果操作被延迟,则发送一个202和一个描述操作结果的实体。 (想象一下代表服务器延迟删除资源的可轮询的“任务”;理论上它可以永远保留在该状态下)。所要做的就是防止客户端以原始forms再次检索它。 响应代码使用410,当“任务”完成或服务器以其他方式删除资源时,返回404。

但是,如果DELETE的语义对于有问题的资源没有意义,也许它不是你正在寻找的删除,而是一个添加状态转换,改变了资源状态,但保持可访问性? 在这种情况下,使用PUT / PATCH来更新资源并完成。

我认为解决这个问题的最RESTful的方法是使用HTTP PUT标记资源删除(和取消删除),然后使用HTTP DELETE永久删除资源。 要获取标记为删除的资源列表,我将使用HTTP GET请求中的参数,例如。 ?state=markedForDeletion 。 如果您请求标记为不带参数的删除资源,我认为您应该返回“404 Not Found”状态。

短版

你不能使用原始URI上的任何方法REST取消删除资源 – 这是不合逻辑的,因为任何试图删除资源的操作都应该返回一个404或410.尽pipe这在规范中没有明确说明,但却强烈暗示在DELETE方法1的定义中(强调增加):

实际上,这种方法类似于UNIX中的rm命令:它在源服务器的URI映射表示删除操作,而不是期望先前关联的信息被删除。

换句话说,当您删除一个资源时,服务器不再将该URI映射到该数据。 所以你不能PUT或POST等等。(请记住,资源被定义为URI和一些基础数据之间的映射)。

一些解决scheme

由于明确指出底层数据不一定被删除,因此不排除服务器将新的 URI映射作为DELETE实现的一部分,从而有效地创build一个可以稍后恢复的备份副本。

你可以有一个“/删除/”集合,其中包含所有删除的项目 – 但你将如何执行撤消删除? 也许最简单的RESTful方法是让客户端使用GET检索项目,然后将其发布到所需的URL。

如果你需要能够将删除的项目恢复到原来的位置呢? 如果您使用支持它的媒体types,则可以将原始URI包含在来自/ deleted / collection的GET响应中。 客户端然后可以使用它来发布。 JSON中的这种响应可能如下所示:

 { "original-url":"/some/place/this/was/deleted/from", "body":<base64 encoded body> } 

客户端然后可以将该主体发布到该URI以执行取消删除。

或者,如果你的资源定义允许移动的概念(通过更新“位置”属性或类似的东西),那么你可以做一个部分更新,避免整个对象的往返。 或者,做大多数人做的事情,并实施类似RPC的操作来告诉服务器移动资源! 不可靠的,是的,但在大多数情况下,它可能会正常工作。

你如何决定这些事情

关于你如何决定这些事情的问题:你必须考虑在你的应用程序的上下文中删除的意思,以及为什么你需要它。 在很多应用程序中,没有任何东西会被删除,“删除”的意思只是“从所有进一步的查询/列表中排除这个项目,除非我明确地取消删除它”。 所以,这实际上只是一个元数据或移动操作。 在这种情况下,为什么要打扰HTTP DELETE? 一个原因可能是,如果你想要一个2层删除 – 一个软或临时版本是可撤销的,一个硬/永久版本是,好吧…不。

没有任何具体的应用上下文,我倾向于像这样实现它们:

我不想再看到这个资源,为了我的方便POST部分更新将资源标记为“暂时删除”

我不希望任何人能够再次访问这个资源,因为它令人尴尬/导致/花费我钱/ etcHTTP DELETE

下一个需要考虑的问题是:永久删除是否应该永久地取消映射URI,以便任何人都不能再链接到它,或者是否有必要清除底层数据呢? 显然,如果你保存了这些数据,pipe理员甚至可以恢复一个“永久”被删除的资源(不是通过任何RESTful接口)。 这样做的缺点是,如果数据的所有者真的希望清除数据,那么pipe理员必须在REST界面之外这样做。