Rest 修改命名资源的下属的正确HTTP方法是什么?

Rest 修改命名资源的下属的正确HTTP方法是什么?,rest,http,http-method,Rest,Http,Http Method,我正在创建一个web客户端,其目的是通过向一组数据库表添加记录并从中删除记录来修改它们。它必须以原子方式执行,因此删除和插入都必须通过单个HTTP请求完成。显然,这是某种写入操作,但我很难确定哪种方法是合适的 POST一开始似乎是正确的,只是POST请求必须描述命名资源的新下属。这不是我在这里要做的 PUT可用于对现有内容进行更改,因此这似乎是正确的,但PUT请求中的URI标识了请求中包含的实体[…],并且服务器不得尝试将请求应用于其他资源,这排除了该方法,因为我的URI没有直接指定数据库表 补

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

POST一开始似乎是正确的,只是POST请求必须描述命名资源的新下属。这不是我在这里要做的

PUT可用于对现有内容进行更改,因此这似乎是正确的,但PUT请求中的URI标识了请求中包含的实体[…],并且服务器不得尝试将请求应用于其他资源,这排除了该方法,因为我的URI没有直接指定数据库表

补丁似乎更接近了——现在我并不是通过部分覆盖一个资源来作弊——但是这个方法,像PUT一样,实际上必须修改URI指定的资源,而不是某个从属资源

那么我应该用什么方法呢

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

对于对X的请求,您可以使用

要创建X的新下属, 要创建新的X, 修改X。 但是,如果要修改X的下属,应该使用什么方法呢?

开始。。不是每件事都需要休息。如果剩下的是你的锤子,一切看起来都像钉子

如果你真的想符合REST的理想,补丁是不可能的。你只需要转移状态

因此,这个问题的常见“解决方案”是在您已有的资源之外工作,但要发明一种新的资源来表示您希望执行的“事务”。此事务可以包含有关您按顺序(可能是原子方式)执行的操作的信息

这允许您放置或发布事务,如果需要,还可以获取事务的当前状态,以确定它是否成功


然而,在大多数设计中,这并不是真正合适的,您应该回到POST并定义一个简单的rpc样式操作,您可以在父级上执行。

RFC2616已经过时。请特别阅读RFC 723*。

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

这篇文章是关于创造一个全新的资源。您将一些数据发送到服务器,并期望得到一个响应,说明新资源是在哪里创建的。我们的期望是,如果您发布到/things/中,新资源将存储在/things/theNewThing/中。通过POST,您可以将其留给服务器来决定所创建资源的名称。发送多个相同的POST请求会导致多个资源,每个资源都有自己的“东西”和自己的URI,除非服务器有一些额外的逻辑来检测重复的内容

PUT主要是关于创建一个资源。PUT和POST之间的第一个主要区别是PUT让客户机控制URI。一般来说,你并不真的想要这个,但这就是重点。PUT所做的另一件事不是修改,如果您仔细阅读规范,它会声明您用一个全新的版本替换URI中的任何资源。这看起来像是在修改,但实际上只是同一URI上的一个全新资源

正如其名称所示,补丁用于修补资源。向服务器发送一个数据,描述如何修改特定资源。考虑一个巨大的资源,补丁允许你只发送你希望改变的一点点数据,而放置则需要你发送整个新版本。

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

{ "add": [
  { /* a resource */ },
  { /* a resource */ } ],
  "remove" : [ "id one", "id two" ] }
在这个主体中,我们将数据发送到服务器,以便在服务器中创建两个资源和删除两个资源。现在,这有一个退步,那就是很难让客户知道发生了什么。这两个新资源的客户端没有“正确”的方式,204创建在某种程度上是这样的,但这意味着有一个用于一个新资源的URI的头。。。但是我们增加了两个。遗憾的是,不管怎样,这都是您将要面对的一个问题,HTTP simple并不是为同时处理多个资源而设计的

事务资源

所以这是人们提出的一个普遍的解决方案,我认为这很糟糕。基本思想是,首先在服务器上发布/放置一个数据块,然后对希望进行的事务进行编码。然后使用另一种方法“激活”此事务

好吧,等等。。。这是两个请求
... 它发送的数据与您通过修补程序发送的数据相同,然后为了以某种方式“激活”此事务,您需要伪造HTTP甚至更多。更重要的是,我们现在有了这个“事务”资源!我们该怎么办

我知道这个问题很久以前就有人问过了,但我想我应该自己对此做出一些评论。这实际上并不是一个真正的答案,而是对科什曼答案的回应。不幸的是,我无法评论他的回答,这将是正确的做法,但我没有足够的声誉,这是一个奇怪的和不必要的概念,伊姆霍

那么,现在让我谈谈我对@thecoshman的评论:

您似乎在质疑事务性资源的概念,但在您的回答中,我认为您可能误解了它们的概念。在您的回答中,您描述了您首先对资源和关联事务进行POST,然后发布另一个资源以激活此事务。但我相信事务性资源的概念在某种程度上是不同的

让我举一个简单的例子:

在一个系统中,您有一个客户资源和他的地址,其中客户是主要的或命名的资源,地址是次要的地址。对于本例,假设我们有一个customerId为1234的客户。到达该客户的URI将是/api/customer/1234。那么,您现在如何只更新客户的地址而不必更新整个客户资源?您可以定义一个名为updateCustomerAddress的事务资源。这样,您就可以将更新后的客户地址数据JSON甚至XML发布到以下URI:POST/api/customer/1234/updateCustomerAddress。然后,服务将创建这个新的事务性资源,以应用于customerId=1234的客户。创建事务资源后,调用将返回201,尽管实际更改可能尚未应用于客户资源。因此,后续的GET/api/customer/1234可能返回旧地址,或者已经返回新的和更新的地址。这很好地支持异步模型来更新从属资源,甚至是命名资源

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


正如您所看到的,事务性资源不需要对一个服务进行两次HTTP调用,只需一次即可完成。

第一件事优先。如果您想像Restfull应用程序一样使用正确的HTTP方法,那么如果您将表视为资源,则不应该让一个请求涉及多个资源。如果所有这些更新表示单个资源的单个更改,那么您应该使用PUTI,因为它认为从属资源是由多个表描述的聚合实体-它不是我可以有指针指向的单个对象,但它是一个概念抽象,建立在数据库结构之上,通过为支持该抽象而编写的过程进行操作。你能证明为什么PUT是正确的,即使URI没有命名要更改的资源吗?为了澄清一点,要修改的实际资源(特定的数据库抽象)是由请求体中的一个参数指定的。因此,URI绝对不是它的唯一标识符,而是标识执行一些预处理的请求处理程序。@PlínioPantaleão一个REST请求影响许多资源没有什么错,只要它们通过一个逻辑资源这样做。请记住,客户机处理的表示与服务器实际存储数据的方式无关。@Coshman这就是我在parentesis中加入的原因,我假设每个表表示一个资源。我知道这没有必要是真的,但这是我对问题的理解,关于不必休息的观点很受欢迎——我真的只想调查符合性的可行性,但最后我会使用一个奇怪的GET,如果这似乎是最好的。但是我不清楚你文章的其他部分。特别是:1我已经有了一个专门用于事务的资源—一个与我的数据库通信的ASP页面—并且我已经能够放置或发布到它,但这并不能帮助我确定要使用的正确动词。2我不知道您所说的rpc样式的操作是什么意思,也不知道这如何构成事务资源的替代方案。我认为您需要更加具体才能得到具体的答案,但我的一般观点是。。您可能只想使用POST和rpc样式的操作,我的意思是:主体可能包含有关操作/函数调用的信息,而不是简单的资源状态传输。补丁是最重要的
这是解决这个问题的方法。您希望对“数据库”资源进行部分修改。您的主体将类似于{delete:[],create:[]}。“你正在向州政府发送一个补丁,如果你愿意的话,这是一个三角洲。”从一个纯粹的“最佳工作工具”的角度来看,你可能是对的。我的观点是,如果你在学业上坚持休息,就根本不应该进行修补手术。@Evert我真的很好奇你的理由。嗯,我不知道。我是否应该认为这意味着,在新的、更模糊的POST定义下,你主张使用这种方法来处理这类事情?