修改指定资源的下级的正确HTTP方法是什么?

时间:2014-10-08 21:19:36

标签: rest http http-method

我正在创建一个Web客户端,其目的是通过向它们添加记录并从中删除记录来修改一组数据库表。它必须以原子方式执行,因此删除和插入都必须使用单个HTTP请求完成。显然,这是某种写入操作,但我很难确定哪种方法是合适的。

POST 一开始似乎没错,但POST请求必须描述的RFC 2616 specifies"新的下属"命名资源。这不是我在这里做的事情。

PUT 可以用来对现有的东西进行更改,所以这似乎是正确的,除了RFC 2616 also specifies" PUT请求中的URI标识附带的实体请求[...]和服务器绝不能尝试将请求应用于其他资源,"由于我的URI不直接指定数据库表,因此规则该方法。

PATCH 似乎更接近了 - 现在我不会因为部分覆盖资源而作弊 - 但RFC 5789 makes it clear此方法(如PUT)必须实际修改URI指定的资源,而不是某些从属资源。

那么我应该使用什么方法?

或者,更广泛地说是为了其他用户的利益:

对于X的请求,请使用

  • POST创建一个新的X下属,
  • PUT创建一个新的X,
  • PATCH修改X。

但是如果你想修改X的下属,你应该使用什么方法?

4 个答案:

答案 0 :(得分:0)

要开始..并非所有都是REST。如果REST是你的锤子,那么一切看起来都像钉子一样。

如果你真的想要符合REST理想,PATCH是不可能的。你真的应该转移国家。

因此,此问题的常见“解决方案”是在您已有的资源之外工作,但发明一个代表您希望执行的“交易”的新资源。此事务可以包含有关您正在执行的操作的信息,可能是原子的。

这允许您PUT(或者POST)交易,并且如果需要,还可以GET交易的当前状态以确定它是否成功。

在大多数设计中,这不太合适,你应该回到POST并定义一个简单的rpc风格的动作你在父母身上执行。

答案 1 :(得分:0)

RFC 2616已过时。请改为阅读RFC 723 *,特别是http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7231.html#POST

答案 2 :(得分:0)

首先,请允许我纠正您对这些方法的理解。

POST 就是要创建一个全新的资源。您将一些数据发送到服务器,并期望回复说明创建此新资源的位置。期望是,如果您POST/things/,新资源将存储在/things/theNewThing/。使用POST将其留给服务器以确定创建的资源的名称。发送多个相同的POST个请求会产生多个资源,每个资源都是他们自己的'使用自己的URI(除非服务器有一些额外的逻辑来检测重复项)。

PUT 主要是关于创建资源的PUTPOST之间的第一个主要区别是PUT让客户端控制URI。一般来说,你并不是真的想要这个,但是这一点已经明白了。 PUT做的另一件事,不是修改,如果您仔细阅读规范,它会声明您使用全新版本替换URI中的资源。这有一种修改的外观,但实际上只是同一URI上的全新资源。

PATCH 用于PATCH资源,顾名思义。您将数据发送到服务器,描述如何修改特定资源。考虑一个巨大的资源,PATCH允许您发送您想要更改的一小部分数据,而PUT则需要您发送整个新版本。

接下来,考虑资源。您有一组表,每个表都有许多行,相当于一组包含许多资源的集合。现在,您的问题是您希望能够以原子方式添加资源并同时删除它们。所以你不能POST然后DELETE,因为它显然不是原子的。 PATCH表格怎么可能......

{ "add": [
  { /* a resource */ },
  { /* a resource */ } ],
  "remove" : [ "id one", "id two" ] }

在这一个机构中,我们已将数据发送到服务器,以创建两个资源并删除服务器中的两个资源。现在,有一个退缩,那就是很难让客户知道发生了什么。没有'适当的'两个新资源的客户端的方式204 created就是那种,但是意味着有一个一个新资源的URI标题......但我们添加了两个。遗憾的是,无论如何,这都是您要面对的问题,HTTP简单并不是为了同时处理多个资源而设计的。

交易资源

所以这是人们提出的常见解决方案,我认为这很糟糕。基本的想法是,您首先在服务器上POST / PUT编码您想要进行的交易。然后,您可以使用其他方法来激活'这笔交易。

好了......那两个请求......它会发送你通过PATCH发送的相同数据,然后你会更多地拥抱HTTP,以便以某种方式“激活” #39;这笔交易。更重要的是,我们有这个'交易'资源现在浮动!我们甚至做了什么?

答案 3 :(得分:0)

我知道这个问题已经提前一段时间了,但我想我应该自己提一些评论。这实际上不是一个真正的回答"但回应了该人的回答。不幸的是,我无法评论他的答案,这是正确的做法,但我没有足够的声誉和#34;这是一个奇怪的(和不必要的)概念,恕我直言。

所以,现在我对@thecoshman的评论:

您似乎质疑"交易资源的概念"但在你的回答中,我认为你可能误解了它们的概念。在您的回答中,您描述了您首先使用资源和关联的事务执行POST,然后将另一个资源POST到"激活"这笔交易。但我相信交易资源的概念在某种程度上是不同的。

让我举个简单的例子:

在一个系统中,你有一个"客户"资源和他的地址与客户作为主要(或命名)资源,地址是从属地址。对于此示例,我们假设客户的customerId为1234.到达此客户的URI为/api/customer/1234。那么,您现在如何更新客户的地址而无需更新整个客户资源?您可以定义一个"交易资源"调用" updateCustomerAddress"。然后,您可以POST更新客户地址数据(JSON甚至XML)到以下URI:POST /api/customer/1234/updateCustomerAddress。然后,该服务将创建此新事务资源,以使用customerId = 1234应用于该客户。创建事务资源后,调用将返回201,尽管实际更改可能尚未应用于客户资源。因此,后续GET /api/customer/1234可能会返回旧地址,或者已经返回新地址。这非常支持用于更新下级资源甚至命名资源的异步模型。

我们将如何处理创建的交易资源?它对客户端完全不透明,并在事务完成后立即丢弃。因此,调用实际上可能不会返回事务资源的URI,因为它可能在客户端尝试访问它时已经消失了。

正如您所看到的,事务性资源不应该要求对服务进行两次HTTP调用,而只能在一次服务中完成。