3

这是我在这个地方找不到相同问题的少数时刻之一,所以我试图描述我的问题并希望得到一些帮助和想法!

比方说...

我想为域模型设计一个 RESTful API,它可能具有如下实体/资源:

class Product
{
    String id;
    String name;
    Price price;
    Set<Tag> tags;
}


class Price
{
    String id;
    String currency;
    float amount;
}


class Tag
{
    String id;
    String name;
}

API 可能如下所示:

GET /products
GET /products/<product-id>
PUT /prices/<price-id>?currency=EUR&amount=12.34
PATCH /products/<product-id>?name=updateOnlyName

在更新参考文献时:

PATCH /products/<product-id>?price=<price-id>
PATCH /products/<product-id>?price=

可以将产品的价格参考设置为另一个现有价格,或删除此参考。

但是如何将现有标签的新引用添加到产品中?

如果我想将该引用存储在关系数据库中,我需要一个用于多对多关系的关系表“products_tags”,这为我们带来了一个明确的解决方案:

POST /product_tags [product: <product-id>, tag: <tag-id>]

但是基于文档的 NoSQL 数据库(如 MongoDB)可以将其存储为每个产品的一对多关系,因此我不需要为必须创建以保存关系的“新资源”建模。

POST /products/<product-id>/tags/ [name: ...]
    creates a new Tag (in a Product),

PUT /products/<product-id>/tags/<tag-id>?name=
    creates a new Tag with <tag-id> or replaces an existing 
    Tag with the same id (in a Product),

PATCH /products/<product-id>?tags=<tag-id>
    sets the Tag-list and doesn't add a new Tag, and

PATCH /products/<product-id>/tags/<tag-id>?name=... 
    sets a certain attribute of a Tag.

所以我可能想说一些链接这个:

ATTACH /products/<product-id>?tags=<tag-id>
ATTACH /products/<product-id>/tags?tag=<tag-id>

所以重点是:

我不想创建新资源,

我不想设置资源的属性,但是

我想将资源添加到另一个资源属性,这是一个集合。^^

由于一切都与资源有关,因此可以说:

我想将资源附加到另一个资源。

我的问题:哪种方法是正确的,URL 应该是什么样子?

4

1 回答 1

3

您的 REST 是应用程序状态驱动程序,并非旨在反映您的实体关系。

因此,在 REST 中没有“如果数据库中是这种情况”。也就是说,你有很好的 URI。

你谈论身份证。什么是标签?标签不是一个简单的字符串吗?为什么它有一个id?为什么它的 id 不是它的名称字符串?

为什么没有PUT /products/<product-id>/tags/tag_name=

PUT 是幂等的,因此您基本上是在断言product-id. 如果您多次发送此请求,您将获得201 Created第一次和200 OK下一次。

如果您正在构建一个简单的系统,其中单个并发用户在单个 Web 服务器上运行,请求中没有并发,您现在可能会停止阅读

如果中间有人删除了该标签,您的下一个 put 请求将重新创建该标签。这是你想要的吗?

使用乐观并发控制,您将每次传递文档的 ETag a409 Conflict ,如果您在服务器上有更新的版本b并且 diffa..b无法协调,则返回。在标签的情况下,您只是使用 PUT 和 DELETE 动词;所以你不必区分/查看和解。

如果你正在构建一个中等先进的并发系统,具有先写者获胜的语义,在单个服务器上运行,你现在可以停止阅读

也就是说,我认为您没有考虑过您的交易边界。你在修改什么?资源?,您正在修改product资源的值对象;它的标签。那么,根据您的资源模型,您应该使用PATCH. 你关心并发吗?那么,关于 PATCH,您还有更多需要考虑的事情:

HTTP PATCH 的 RFC 是这样说的:

然而,对于 PATCH,封闭的实体包含一组指令,描述如何修改当前驻留在源服务器上的资源以生成新版本。PATCH 方法会影响 Request-URI 标识的资源,也可能对其他资源产生副作用;即,可以通过应用 PATCH 创建新资源或修改现有资源。

正如 [RFC2616] 第 9.1 节所定义的那样,PATCH既不安全也不幂等。

我现在可能不会再把奇怪的想法放在你的脑海里了。如果您希望我继续沿着这条路走更长的时间,请发表评论;)。可以说,还有更多的考虑可以做。

于 2012-04-05T10:36:16.063 回答