是否可以通过PUT或DELETE部分更改集合?


21

我在一个产品组中有一个产品集合,例如:

product-groups/123/products
  1. 如果我需要添加到集合中,可以通过PUT 只传递某些产品吗?

  2. 如果我需要从集合中删除某些产品,可以通过DELETE 传递过滤器数据(ID数组)吗?

秉承ReST精神实现功能的最佳方法是什么?

编辑:项目是指向单独实体(基本上是产品ID)的链接。


产品组中的项目是在其他地方管理的单独资源吗?还是它们只是产品组集合的一部分?如果分开,产品可以属于多个产品组吗?
马丁·皮耶特

2
也许PATCH 该规范定义了新的HTTP / 1.1 [RFC2616]方法PATCH,该方法用于对资源进行部分修改。
Esailija

一个产品(ID)可以属于几个产品组。
2013年

有没有一种众所周知的方式(最佳实践)来说明如何进行修补,即在集合中添加或删除产品?
2013年

Answers:


10

通常,您有一个端点表示x的整个集合:

/products

假设您要更新单个产品,然后将其放置/products/{id}。如果您要部分更新单个产品(而不是更新每个字段),则也可以使用PATCH/products/{id}。删除单个实体(DELETE to /products/{id})也是如此。

如果要定位单个资源,则可以通过路径限定要修改的单个资源。

破坏方案的唯一动作是资源的创建。创建资源时,您将整个集合作为目标,说POST/products

也就是说,应该明确的是,影响整个集合的操作目标应该转到适当的集合端点。

例如,您要检索红色的产品子集,则要求

GET/products?colour=red

因此,如果要删除所有这些,则请DELETE /products?colour=red。或者,如果您想通过删除某些产品id,则可以删除 /products?id=1&id=2&id=3

怎么样批量创建 ressources的?POST您的收藏[{...},{...},{...}]干脆/products。这同样适用于PUTPATCH

那真的很简单。

要回答您的问题:

如果我需要添加到集合中,可以通过PUT仅传递某些产品吗?

不仅可以,还建议您这样做。

如果我需要从集合中删除某些产品,可以通过DELETE传递过滤器数据(ID数组)吗?

没关系。正如Eneko Alonso所写的那样,有时通过“控制器” 端点封装了批量操作,即使用POST来触发(复杂)操作。


2
PUT是替换操作。在具有“某些产品”的集合终结点上调用PUT应该删除(在OP的情况下,删除与之的关系)“某些产品”列表中未包括的任何产品。虽然它可以用来添加项目,但它也应该删除项目(我认为)不是OP期望的项目。您应该相应地修改对他们的第一个问题的回答。
claytond

@claytond:我想答案是好的,只要通过进行部分更新PATCH,并通过进行完全替换PUT
9000

4
@ 9000。当然,但是当前的答案是“鼓励您...仅通过某些PUT将产品添加到……中”。那肯定是不正确的。鼓励发布。能够放入...但只能通过传递所有(而非某些)物品。
claytond

5

通常,REST方法旨在在单个实体/对象(CRUD)上运行。

有几种选择:

  • 将您的收藏集视为实体,并通过POST更新它们
  • 创建备用的非REST操作

第一个遵循REST标准,但是可能很昂贵,因为您的收集对象/实体可能非常大(更新拥有数千个产品的组仅添加/删除一个产品将是一个沉重的要求)。

第二个选项是许多API首选的,这是将REST扩展到CRUD操作之外的一种方法。

例如:

GET product-groups/123/products (list all the products in the group)
POST product-groups/123/products/append (POST a list of new product ids to append to the group)
POST product-groups/123/products/remove (POST a list of product ids to remove from the group)

许多API始终使用POST进行此扩展操作,但没有任何限制可以使用其他http方法(除了GET和DELETE的局限性之外,它具有一个空的正文)


当然,有几种方法可以达到目标。最佳做法是哪一种?哪一个会更适合未来?
2013年

4
@ user151851:完全符合REST(如果有的话)是一个崇高的目标。这里的方法概述似乎更加现实,因为它试图采用一种在“现实世界”中实际使用的方法,实质上使它成为了事实上的标准。这与您将要获得的面向未来的一样。
罗伯特·哈维

2
我们不使用URL中的“添加”和“删除”引入自定义动词吗?这样,我们将不得不解释如何使用API​​。我们不应该重用我们现有的HTTP方法吗?在这种情况下,动作是众所周知的。
user151851 2013年

7
对于碰到这个答案的其他人:这是错误的。正如@ user151851所提到的,这会将动词引入URL中,这与您获得的非RESTful差不多。关于实际问题,我没有一个很好的答案,但这不是。
umbrae

通过使其products/collection返回项目的“信封”和通过PUT更改信封内容的“扩展名”,是否可以更加面向资源?就像,“这正是我想要集合中的项目的样子”。
路加·普普利特

3

仅用于精确的先前答案/评论。

据我所知,POST是将单个元素添加到集合中的方法。

反过来,DELETE是从集合中删除单个元素的方法。两种方案都是完全RESTful的。

但是,您应该使用适当的URI来引用单个元素或整个集合。

例如,要将元素添加到集合中,您应该将数据发布到以下URI:

https://www.factory.net/products/

要从集合中删除单个产品,您可以使用DELETE方法将请求发送至以下内容:

https://www.factory.net/products/108/

PATCH方法可用于更新集合中的某些元素。例如,当您只需要更新一个元素中的一个字段时。为很大的集合放置完整的资源表示形式可能是非常昂贵的操作。


2

原则上,所有RESTful操作对集合都有效,但是请确保您了解动词的语义如何应用于集合:

  • PUT是完全替代品。

    • 如果您将PUT放到一个单例中(例如/item/{id}),然后将name其忽略,则应将其清除或设置为null或类似的内容。
    • 如果您将一个PUT放入一个集合中,但不包括某个项目,则应将从该集合中删除

    虽然可以使用PUT添加项目,但必须发送“所有”项目。发送“某些”项目应导致删除(我想这不是OP想要的)。

  • DELETE更直观。删除集合或其任何过滤的子集是有效的。仅过滤器中包含的项目应受到影响。

  • PATCH也有效。从理论上讲,您应该提供“操作”列表。例如,从技术上讲,您应该发送以下内容:

    [{ 
        "action": "update",
        "id": <id>,
        "value": {...}
    },{
        "action": "add",
        "value": {...}
    }, ...]
    

    在实践中,更常见的情况是看到一个API接受部分对象列表,其中使用UPSERT(更新或插入)逻辑处理各项的对象。

  • 从技术上讲,POST应该“根据资源自身的特定语义”处理输入。

    • 实际上,POST通常用于“创建”操作。
    • 但是,POST也是用于非标准呼叫的动词。尽管人们对操作端点是否严格依赖RESTful(我赞成“否”)进行了激烈的争论,但如果您要向端点提交请求,则POST是合适的动词{resource}/activate

注意:在集合上使用非GET操作时,请仔细考虑成功和失败的定义。REST并没有给您传达部分成功的好方法。一个很好的默认值是假设您将在成功或不成功的事务中运行该操作。如果这不是您想要的,则可能不应该直接与集合进行交互。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.