在REST Api调用中批量更新集合的最佳实践

时间:2016-04-13 12:03:17

标签: api rest api-design

您好我正在寻找API设计的最佳实践,以便通过API调用批量更新集合。

我的收藏品有URL / api / v1 / cars,我想更新收藏中的所有汽车,以添加当前时间的时间戳。

{
    data: [
    {
        manufacturer: 'Porsche',
        timestamp: ...
    },
    {
        manufacturer: 'BMW',
        timestamp: ...
    }
    {
        manufacturer: 'Peugeot',
        timestamp: ...
    }
}

我想了几个选项,但我无法确定最佳做法是什么。

应该是:

1 /建模为另一种资源,例如POST api/v1/cars/updateTimestamp

2 /作为查询参数传递:PUT api/v1/cars?updateTimestamp

3 /传递请求正文:

POST api/v1/cars 
{"operation":"Update timestamps"}

我想强调整个处理应该在后端完成而不是由客户端传递。 对于后端发生的任何复杂处理,都会发生同样的问题。 在这种情况下,我如何保留API RESTy。

非常感谢您的帮助/任何指向相关资源的指针。

2 个答案:

答案 0 :(得分:4)

由于HTTP中没有定义部分PUT,您需要发送每个资源的整个实体进行更新或使用其他一些操作。

POST

由于POST是一个通用操作,您可以使用它在服务器上创建一个短期临时资源(甚至不需要own URL)。收到后,服务器可以使用一些提供的字段值组合更新所有指定的条目或所有条目(如果在关系数据库中尚不知道该列,则可能需要某些表格更改)

一个简单的请求可能如下所示:

POST /api/v1/cars/addAttributes HTTP/1.1
Host: example.org
Content-Length: 24
Content-Type: application/json
If-Match: "abc123"

{
  "timestamp": "..."
}

这种方法的优点是,即使不事先了解当前状态,也可以随时将其发送到服务器。然而,这也存在某些条目得到更新的危险,这些条目不应受到影响。这可以通过指定If-Match标头来影响,该标头指向某个版本哈希并在每次实体更新时更改,或者通过向服务器也必须理解的JSON主体添加某个限制器来影响。 / p>

PATCH

类似于POST,它可以直接向服务器发送任何内容,PATCH用于修改资源。单个请求明确可以一次更新多个资源,但是,客户端需要定义将资源从状态A转换为状态B的必要步骤。因此,客户端还需要具有资源的最新状态才能成功将资源转换为其最新状态( - > ETag和If-Modified HTTP标头)

对提供的示例的JSON Patch请求可能如下所示:

PATCH /api/v1/cars HTTP/1.1
Host: example.org
Content-Length: 215
Content-Type: application/json-patch+json
If-Match: "abc123"

[
  { "op": "add", "path": "/data/1", "value": [ "timestamp", "..." ] },
  { "op": "add", "path": "/data/2", "value": [ "timestamp", "..." ] },
  { "op": "add", "path": "/data/3", "value": [ "timestamp", "..." ] }
]

其中/data/1/data/2/data/3PorscheBMWPeugeot资源的唯一标识符。

PATCH指定请求必须是原子的,这意味着全部或全部指令都不成功,这也会给表带来一些事务要求。

讨论

如前所述,在POST请求中,只要服务器能够理解您要发送的内容,您就可以将任何想要的内容发送到服务器。因此,您需要如何设计请求结构(以及服务器逻辑)。

另一方面,

PATCH,尤其是JSON Patch定义了一些严格的规则和预定义的操作,通常用于传统的修补。交易要求可能是一种负担,但也是一种好处。除此之外,PATCH还不是最终的,但仍然在RFC中,尽管它已经广泛使用。

答案 1 :(得分:1)

我会做一个PUT来做一个更新操作。 PUT用于更新对象,POST用于创建。您可以使用查询参数指定字段。

  • POST / api / v1 / cars>创造新车
  • PUT / api / v1 / cars>根据对象中的id更新汽车。你可以 如果你想使用没有的路由,也可以创建一个cars /:id路由 id对所有汽车对象进行更新(这似乎不会发生在 许多应用程序)。
  • GET / api / v1 / cars>列出所有车辆
  • GET / api / v1 / cars /:id>列出一辆车。

回答你的问题。您想要更新所有汽车对象。在这种情况下,我会使用PUT / api / v1 / cars并指定/ api / v1 / cars /:id来对一辆车进行更新,但我不明白为什么要实现这一点。如果是一次性操作,我会更新数据库中的所有汽车,而不是创建API路径。