为什么使用两步法使用 REST 删除多个项目 [英] Why use two step approach to deleting multiple items with REST

查看:49
本文介绍了为什么使用两步法使用 REST 删除多个项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们都知道通过 REST 删除单个项目的标准"方式是向 URI example.com/Items/666 发送单个 DELETE 请求.Grand,让我们继续一次删除多个.由于我们不需要原子删除(或真正的事务,即全有或全无),我们可以只告诉客户端运气不好,发出很多请求",但这不是很好.因此,我们需要一种方法来允许客户端请求一次删除多个项目".

根据我的理解,此问题的典型"解决方案是两步"方法.首先,客户端 POST 一个项目 ID 列表并返回一个 URI,例如 example.com/Items/Collection/1.创建该集合后,他们会对其调用 DELETE.

现在,我发现这很好用,但对我来说,这是一个糟糕的解决方案.首先,您强制客户端发出两个请求以容纳服务器.其次,我认为 DELETE 应该删除一个项目?",不应该在这个 URI 上调用 DELETE 有效地取消交易(虽然这不是真正的交易),我们如何取消它?如果有某种形式的执行"动作真的会更好,但我不能那样摇晃船.它还迫使服务器必须考虑发布的 JSON 看起来更像是修改这些项目的请求,但请求是 DELETE...所以我想我会删除它们".这种方法也开始在客户端/服务器上强加一种状态,我承认这不是真正的状态,但确实如此.

在我看来,更好的解决方案是简单地在 example.com/Items 上调用 DELETE(或者可能 example.com/Items/Collection 暗示这是多次删除)并传递包含要删除的 ID 列表的 JSON 数据.据我所知,这基本上解决了第一种方法存在的所有问题.作为客户端更容易使用,减少服务器必须做的工作,真正无状态,更具语义.

我真的很感激对此的反馈,我是否遗漏了一些关于 REST 的内容,使我对这个问题的解决方案不切实际?我也很感激文章的链接,特别是如果他们比较这两种方法;我知道这通常不被批准用于 SO.我需要能够反驳只有第一种方法是真正的 RESTfull,证明第二种方法是一个可行的解决方案.当然,如果我说错了,请告诉我.

解决方案

我花了一周左右的时间阅读了一些关于 REST 的内容,据我所知,描述这些解决方案中的任何一个都是错误的作为RESTfull",您应该说两种解决方案都不违背 REST 的含义".

简单的答案就是 REST,正如 Roy Fielding 的论文(参见第 5 章),不涉及如何在 REST 庄园中删除单个或多个资源的主题.没错,没有删除资源的正确 RESTful 方式"......好吧,不完全是.

REST 本身并没有定义如何删除资源,但它确实定义了您使用的任何协议(请记住,REST 不是协议)将决定如何执行这些操作.协议通常是 HTTP;通常"是关键词,因为 Fielding 会指出, REST不是 HTTP 的同义词.

所以我们通过 HTTP 来判断哪种方法是正确的".遗憾的是,就 HTTP 而言,这两种方法都是可行的.是的'可行'.HTTP 将允许客户端发送带有有效负载的 POST 请求(以创建集合资源),然后在此新集合上调用 DELETE 方法以删除资源;它还允许您在单个 DELETE 方法的有效负载中发送数据以删除资源列表.HTTP 只是您向服务器发送请求的媒介,由服务器做出适当的响应.对我来说,HTTP 协议似乎在某些地方对解释相当开放,但它似乎确实为操作的含义、应如何处理和应给出的响应制定了相当明确的指导方针;这只是你应该这样做"而不是你必须这样做",但也许我在措辞上有点迂腐.

有些人会争辩说,两阶段"方法不可能是REST",因为服务器必须为客户端存储一个状态"才能执行第二个操作.这只是对某些部分的误解.必须理解的是,客户端和服务器都没有在列表被发布和随后被删除之间存储任何关于另一个的状态"信息.是的,列表在删除之前必须已经创建,但服务器不记得是客户端 alpha 制作了这个列表(这种方法将允许客户端简单地调用DELETE"作为下一个请求,服务器会记住要使用该列表,这根本就不是无状态的),因此,客户端必须告诉服务器删除该特定列表,该列表为其提供了特定 URI.如果客户端试图删除一个不存在的集合列表,它只会被告知找不到资源"(最有可能是经典的 404 错误).如果您希望声明这两个步骤的方法确实维护了一个状态,您还必须声明简单地 GET 一个 URI 需要一个状态,因为 URI 必须首先存在.声称存在这种状态"持续存在是对状态"含义的误解.作为进一步证明"这种两阶段方法确实是无状态的,您可以很高兴地让客户端 alpha POST 列表,然后客户端 beta(没有与其他客户端进行任何通信)在列表资源上调用 DELETE.

我认为第二个选项(仅在 DELETE 请求的有效负载中发送列表)是无状态的,这是不言而喻的.完成请求所需的所有信息都完全存储在一个请求中.

虽然 DELETE 操作只应在有形"资源上调用,但可能存在争议,但这样做您公然忽略了 REST 的表示部分;就在名字里!它是允许"URI 的代表性方面,例如 http://example.com/myService/timeNow,一个 URI,当 'got' 将动态返回当前时间,而无需加载一些文件或从一些数据库中读取.URI 不直接映射到某些有形"数据是一个关键概念.

然而,必须质疑这种无国籍性质的一个方面.正如 Fielding 在 5.1.3 节中描述的客户端无状态服务器",他指出:

我们接下来为客户端-服务器交互添加一个约束:通信必须本质上是无状态的,如客户端-无状态-服务器 (CSS) 风格第 3.4.3 节(图 5-3),这样从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,以及无法利用服务器上任何存储的上下文.会话状态是因此完全保留在客户端.

在我看来,这里的关键部分是无法利用服务器上存储的任何上下文".现在我要承认,上下文"在某种程度上可以解释.但是我发现很难看出您如何考虑存储一个列表(在内存中或在磁盘上),用于给出实际有用的含义不会违反这个规则".没有这个列表上下文",删除操作就没有意义了.因此,我只能得出结论,使用两步法来执行诸如删除多个资源之类的操作不能也不应该被视为RESTfull".

我也有点不情愿为这两种方式寻找论据而付出的努力.整个互联网似乎已经被这个想法所吸引,两步方法是执行此类操作的RESTfull"方式,推理这是执行它的 RESTfull 方式".如果你从其他人正在做的事情上退一步,你会发现这两种方法都需要发送相同的列表,因此可以从参数中忽略它.这两种方法都是代表性的"和无状态的".唯一真正的区别是由于某种原因,一种方法决定需要两个请求.然后,这两个请求带​​有后续问题,例如您将这些数据保留多长时间"以及客户端如何告诉服务器它不再需要该集合,但希望保留它所引用的实际资源"'.

所以我在某种程度上用同样的问题来回答我的问题,你为什么要考虑两步法?"

We all know the 'standard' way of deleting a single item via REST is to send a single DELETE request to a URI example.com/Items/666. Grand, let's move on to deleting many at once. As we do not require atomic deleting (or true transaction, ie all or nothing) we could just tell the client 'tough luck, make many requests' but that's not very nice is it. So we need a way to allow a client to request many 'Items' be deleted at once.

From my understanding, the 'typical' solution to this problem is a 'two step' approach. First the client POSTs a list of item IDs and is returned a URI such as example.com/Items/Collection/1. Once that collection is created, they call DELETE on it.

Now, I see that this works just fine, except to me, it is a bad solution. Firstly, you are forcing the client to make two requests to accommodate the server. Secondly, 'I thought DELETE was supposed to delete an Item?', shouldn't calling DELETE on this URI effectively cancel the transaction (it's not a true transaction though), how would we even cancel it? Really would be better if there was some form 'EXECUTE' action, but I can't rock the boat that much. It also forces the server to have to consider 'the JSON that was POSTed looks more like a request to modify these Items, but the request was DELETE... so I guess I will delete them'. This approach also starts to impose a sort of state on the client/server, not a true state I will admit, but it is sort of.

In my opinion, a better solution would be to simply call DELETE on example.com/Items (or maybe example.com/Items/Collection to imply this is a multiple delete) and pass JSON data containing a list of IDs that you wish to delete. As far as I can see, this basically solves all the problems the first method had. It is easier to use as a client, reduces the work the server has to do, is truly stateless, is more semantic.

I would really appreciate the feed back on this, am I missing something about REST that makes my solution to this problem unrealistic? I would also appreciate links to articles, especially if they compare these two methods; I am aware this is not normally approved of for SO. I need to be able to disprove that only the first method is truly RESTfull, prove that the second approach is a viable solution. Of course, if I am barking up the wrong tree do tell me.

解决方案

I have spent the last week or so reading a fair bit on REST, and to the best of my understanding, it would be wrong to describe either of these solutions as 'RESTfull', rather you should say that 'neither solution goes against what REST means'.

The short answer is simply that REST, as laid out in Roy Fielding's dissertation (See chapter 5), does not cover the topic of how to go about deleting resources, singular or multiple, in a REST manor. That's right, there is no 'correct RESTful way to delete a resource'... well, not quite.

REST itself does not define how delete a resource, but it does define that what ever protocol you are using (remember that REST is not a protocol) will dictate the how perform these actions. The protocol will usually be HTTP; 'usually' being the key word as Fielding will point out, REST is not synonymous with HTTP.

So we look to HTTP to say which method is 'right'. Sadly, as far as HTTP is concerned, both approaches are viable. Yes 'viable'. HTTP will allow a client to send a POST request with a payload (to create a collection resource), and then call a DELETE method on this new collection to delete the resources; it will also allow you to send the data within the payload of a single DELETE method to delete the list of resources. HTTP is simply the medium by which you send requests to the server, it would be up to the server to respond appropriately. To me, the HTTP protocol seems to be rather open to interpretation in places, but it does seem to lay down fairly clear guide lines for what actions mean, how they should be dealt with and what response should be given; it's just it is a 'you should do this' rather than 'you must do this', but perhaps I am being a little pedantic on the wording.

Some people would argue that the 'two stage' approach cannot possibly be 'REST' as the server has to store a 'state' for the client to perform the second action. This is simply a misunderstanding of some part. It must be understood that neither the client nor the server is storing any 'state' information about the other between the list being POSTed and then subsequently being DELETEd. Yes, the list must have been created before it can deleted, but the server does not remember that it was client alpha that made this list (such an approach would allow the client to simply call 'DELETE' as the next request and the server remembers to use that list, this would not be stateless at all) as such, the client must tell the server to DELETE that specific list, the list it was given a specific URI for. If the client attempted to DELETE a collection list that did not already exist it would simply be told 'the resource can not be found' (the classic 404 error most likely). If you wish to claim that this two step approach does maintain a state, you must also claim that to simply GET an URI requires a state, as the URI must first exist. To claim that there is this 'state' persisting is misunderstanding what 'state' means. And as further 'proof' that such a two stage approach is indeed stateless, you could quite happily have client alpha POST the list and later client beta (without having had any communication with the other client) call DELETE on the list resources.

I think it can stand rather self evident that the second option, of just sending the list in the payload of the DELETE request, is stateless. All the information required to complete the request is stored completely within the one request.

It could be argued though that the DELETE action should only be called on a 'tangible' resource, but in doing so you are blatantly ignoring the REpresentational part of REST; It's in the name! It is the representational aspect that 'permits' URIs such as http://example.com/myService/timeNow, a URI that when 'got' will return, dynamically, the current time, with out having to load some file or read from some database. It is a key concept that the URIs are not mapping directly to some 'tangible' piece of data.

There is however one aspect of that stateless nature that must be questioned. As Fielding describes the 'client-stateless-server' in section 5.1.3, he states:

We next add a constraint to the client-server interaction: communication must
  be stateless in nature, as in the client-stateless-server (CSS) style of
  Section 3.4.3 (Figure 5-3), such that each request from client to server must
  contain all of the information necessary to understand the request, and
  cannot take advantage of any stored context on the server. Session state is
  therefore kept entirely on the client.

The key part here in my eyes is "cannot take advantage of any stored context on the server". Now I will grant you that 'context' is somewhat open for interpretation. But I find it hard to see how you could consider storing a list (either in memory or on disk) that will be used to give actual useful meaning would not violate this 'rule'. With out this 'list context' the DELETE operation makes no sense. As such, I can only conclude that making use of a two step approach to perform an action such as deleting multiple resources cannot and should not be considered 'RESTfull'.

I also begrudge somewhat the effort that has had to be put into finding arguments either way for this. The Internet at large seems to have become swept up with this idea the the two step approach is the 'RESTfull' way doing such actions, with the reasoning 'it is the RESTfull way to do it'. If you step back for a moment from what everybody else is doing, you will see that either approach requires sending the same list, so it can be ignored from the argument. Both approaches are 'representational' and 'stateless'. The only real difference is that for some reason one approach has decided to require two requests. These two requests then come with follow up questions, such as how 'long do you keep that data for' and 'how does a client tell a server that it no longer wants that this collection, but wishes to keep the actual resources it refers to'.

So I am, to a point, answering my question with the same question, 'Why would you even consider a two step approach?'

这篇关于为什么使用两步法使用 REST 删除多个项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆