我正在创建一个Web客户端,其目的是通过向它们添加记录并从中删除记录来修改一组数据库表 . 它必须以原子方式执行,因此删除和插入都必须使用单个HTTP请求完成 . 显然,这是某种写入操作,但我很难确定哪种方法是合适的 .
POST 一开始似乎是正确的,除了RFC 2616 specifies,POST请求必须描述命名资源的"a new subordinate" . 那不是't quite what I'在这里做的 .
PUT 可以用来对现有的东西进行更改,所以这似乎是正确的,除了RFC 2616 also specifies,"the URI in a PUT request identifies the entity enclosed with the request [...] and the server MUST NOT attempt to apply the request to some other resource,"规定了该方法,因为我的URI不直接指定数据库表 .
PATCH 似乎更近了 - 现在我并没有因为只是部分覆盖资源而作弊 - 但RFC 5789 makes it clear这个方法,如PUT,必须实际修改URI指定的资源,而不是某些从属资源 .
那么我应该使用什么方法?
Or, more broadly for the benefit of other users:
对于X的请求,请使用
但是如果你想修改X的下属,你应该使用什么方法?
4 回答
要开始..并非一切都必须是REST . 如果REST是你的锤子,一切看起来都像钉子 .
如果你真的想要符合REST理想,
PATCH
是不可能的 . 你真的应该转移国家 .因此,解决此问题的常见“解决方案”是在您已有的资源之外工作,但发明一个代表您希望执行的“事务”的新资源 . 此事务可以包含有关您正在执行的操作的信息,可能是原子的 .
这允许您
PUT
(或者可能POST
)该事务,并且如果需要,还可以GET
事务的当前状态以查明它是否成功 .在大多数设计中,这不太合适,你应该回到
POST
并定义一个简单的rpc风格的动作,你在父母上执行 .RFC 2616已过时 . 请改为阅读RFC 723 *,特别是http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#POST .
首先,请允许我纠正您对这些方法的理解 .
POST 就是要创造一个全新的资源 . 您将一些数据发送到服务器,并期望回复说明创建此新资源的位置 . 期望是如果您
POST
到/things/
,新资源将存储在/things/theNewThing/
. 使用POST
,您将其留给服务器以确定创建的资源的名称 . 发送多个相同的POST
请求会产生多个资源,每个资源都有自己的'thing'和自己的URI(除非服务器有一些额外的逻辑来检测重复项) .PUT 主要是关于创建资源 .
PUT
和POST
之间的第一个主要区别是PUT
使客户端控制URI . 一般来说,你不应该明白这一点 .PUT
做的另一件事, is not modify ,如果你仔细阅读规范,它就说明你用一个全新的版本替换了URI的资源 . 这有一种修改的外观,但实际上只是同一URI上的全新资源 .PATCH ,顾名思义,是
PATCH
资源 . 您将数据发送到服务器,描述如何修改特定资源 . 考虑一个巨大的资源,PATCH
允许您只发送您希望更改的一小部分数据,而PUT
则要求您发送整个新版本 .接下来,考虑资源 . 您有一组表,每个表都有许多行,相当于一组包含许多资源的集合 . 现在,您的问题是您希望能够以原子方式添加资源并同时删除它们 . 所以你不能只是
POST
然后DELETE
,因为这显然不是原子的 .PATCH
在 table 上怎么可能......在那个机构中,我们已经将数据发送到服务器以创建两个资源并删除服务器中的两个资源 . 现在,有一个回归,这就是它的两个新资源的客户端's hard to let clients know what is going on. There'没有's hard to let clients know what is going on. There'方式,
204 created
就是那里的,但是意味着有一个新资源的URI的头 . ..但我们加了两个 . 遗憾的是,无论如何,这都是您要面对的问题,HTTP简单不是为了同时处理多个资源而设计的 .Transaction Resources
所以这是人们提出的常见解决方案,我觉得它很臭 . 基本的想法是,您首先在服务器上编码您想要进行的事务的数据blob . 然后使用另一种方法'activate'此事务 .
好吧......这是两个请求......它发送的数据与你通过
PATCH
发送的数据相同,然后为了某种方式'activate'这个事务你还有更多的软件HTTP . 什么's more, we have this '交易'资源现在浮动!我们甚至做了什么?我知道这个问题已经提前了一段时间了,但我想我应该自己提一些评论 . 这实际上不是一个真正的“答案”,而是对哥斯达答案的回应 . 不幸的是,我无法评论他的答案,这是正确的做法,但我没有足够的“声誉”,这是一个奇怪的(和不必要的)概念,恕我直言 .
所以,现在我对@thecoshman的评论:
您似乎质疑“交易资源”的概念,但在您的回答中,我认为您可能误解了它们的概念 . 在您的回答中,您描述了您首先使用资源和关联的事务执行POST,然后POST另一个资源以“激活”此事务 . 但我相信交易资源的概念在某种程度上是不同的 .
我举个简单的例子:
在系统中,您有一个"customer"资源,其地址以客户为主要(或命名)资源,地址为从属地址 . 对于此示例,我们假设客户的customerId为1234.到达此客户的URI为
/api/customer/1234
. 那么,您现在如何更新客户的地址而无需更新整个客户资源?您可以定义一个名为"updateCustomerAddress"的"transaction resource" . 然后,您将POST
更新的客户地址数据(JSON或甚至XML)到以下URI:POST /api/customer/1234/updateCustomerAddress
. 然后,该服务将创建此新事务资源,以使用customerId = 1234应用于该客户 . 一旦创建了事务资源,该调用将返回201,尽管实际更改可能尚未应用于客户资源 . 因此,后续GET /api/customer/1234
可能会返回旧地址,或者已经是新的和更新的地址 . 这很好地支持用于更新下级资源甚至命名资源的异步模型 .我们将如何处理创建的事务资源?它对客户端完全不透明,并在事务完成后立即丢弃 . 因此,调用实际上可能不会返回事务资源的URI,因为它可能在客户端尝试访问它时已经消失 .
如您所见,事务性资源不应该要求对服务进行两次HTTP调用,而只能在一次服务中完成 .