RESTful附加到资源的属性

时间:2009-10-15 23:47:59

标签: rest

这是Updating a value RESTfully with Post

的后续行动

如何使用REST简单地附加到资源的属性。想象一下,我有customer.balance和balance是一个int。让我们说我只想告诉服务器将5添加到当前余额中。我可以这样做吗?如果是这样,怎么样?

请记住,客户不知道客户的现有余额,因此不能只是

  1. 获取客户
  2. customer.balance + = 5
  3. 发布客户
  4. (上面也会出现并发问题。)

3 个答案:

答案 0 :(得分:4)

简单,有点丑陋:

这是我answer to your other question的更简单变体。

如果您执行以下操作,我认为您仍处于REST的限制范围内。但是,我很好奇其他人对这种情况的看法,所以我希望听到别人的意见。

您的URI将是:

/customer/21/credits

您将信用资源(可能是<credit>5</credit>)发布到URI,然后服务器可以获取客户的余额,并使用提供的值+=。此外,您可以支持负面信用(例如<credit>-10</credit>);

请注意,/customer/21/credits 不支持所有方法。仅支持POST是完全可以接受的。

但是,如果积分不是您系统中的真正资源,这会有点奇怪。 HTTP spec说:

  

如果在源服务器上创建了资源,则响应应该是201(已创建)并包含描述请求状态的实体,并引用新资源和Location头。

从技术上讲,您不是在这里创建资源,而是追加到客户的余额(实际上系统中所有先前信用的总和)。由于您没有保留信用(大概),您实际上无法返回对新“创建”信用资源的引用。您可能会返回客户的余额或<customer>本身,但这对客户来说有点不直观。这就是为什么我认为将每个信用作为系统中的新资源更容易使用(见下文)。

我的首选解决方案:

这是根据你在其他问题中的回答改编的。在这里,我将尝试从客户端/服务器正在做的事情的角度来处理它:

  • 客户端:

    1. 建立新的信用资源:

      <credit>
        <amount>5</amount>
      </credit>
      
    2. 将资源发布到/customer/21/credits

      在此处发帖意味着,“将此新<credit>添加到此客户的<credit>列表中。

  • 服务器:

    1. 收到/customer/21/credits
    2. 的POST
    3. 从请求中获取金额,并将+=更改为客户的余额
    4. 保存信用及其信息以供日后检索
    5. 向客户发送回复:

      <credit href="/customer/21/credits/credit-id-4321234">
        <amount>5</amount>
        <date>2009-10-16 12:00:23</date>
        <ending-balance>45.03</ending-balance>
      </credit>
      

这为您提供了以下优势:

  • 可以在以后通过ID(使用GET /customer/21/credits/[id]
  • 访问学分
  • 您有完整的信用记录审核跟踪
  • 如果您支持,客户可以通过ID更新或删除信用(使用PUT或DELETE)
  • 如果您支持,客户可以检索有序的信用列表;例如GET /customer/21/credits可能会返回:

    <credits href="/customer/21/credits">
       <credit href="/customer/21/credits/credit-id-7382134">
         <amount>13</amount>
         ...
       </credit>
       <credit href="/customer/21/credits/credit-id-134u482">
         ...
       </credit>
       ...
    </credits>
    
  • 有道理,因为客户的余额实际上是应用于该客户的所有信用的最终结果。

答案 1 :(得分:0)

要以REST-ful的方式考虑这一点,您需要将行动本身视为一种资源。例如,如果这是银行业务,并且您想要更新帐户余额,则需要创建存款资源,然后添加其中一个。这样做的结果是更新客户的余额

这也有助于解决并发问题,因为您将提交+5操作,而不需要事先了解客户的余额。并且,您还可以回忆起该资源(例如存款/ 51存款,ID为51)并查看其他详细信息(即存款原因,存款日期等)。

编辑:意识到使用5的ID作为存款实际上会混淆问题,因此将其更改为51.

答案 2 :(得分:0)

嗯,除了@ Rob-Hruska的解决方案之外还有其他选择。

基本思路是一样的:将每个信用/借记操作视为独立交易。但是我曾经使用过支持在json中存储无模式数据的后端,因此我最终将API定义为带有动态字段名称的 PUT 。像这样:

PUT /customer/21

{"transaction_yyyymmddHHMMSS": 5}

我知道这在“信用/借记”上下文中是不合适的,因为活动帐户可能会有不断增长的交易记录。但在我的背景下,我使用这样的策略存储有限数据(实际上我在驾驶旅程中存储了不同批次的GPS路点)。

缺点:这种api风格严重依赖后端行为的无模式功能。

优点:从语义的角度来看,至少我的方法完全是RESTful。

相比之下,@ Rob-Hruska的“简单,稍微丑陋”的解决方案1没有在“201 Created”响应中返回有效的Location头,这不是常见的RESTful行为。 (或者,也许,我们可以让@ Rob-Hruska的解决方案1也返回一个虚拟的Location头,它指向“410 Gone”或“404 Not Found”页面。这更加RESTful吗?欢迎评论!)