什么是将一种资源附加到另一种资源的RESTful方式?

时间:2012-04-04 15:20:21

标签: http rest nosql

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

让我们说......

我想为域模型设计一个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>

所以重点是:

我不想创建新资源

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

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

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

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

我的问题:哪种方法是正确的,网址应该如何?

1 个答案:

答案 0 :(得分:2)

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

因此,在REST中没有'如果这是db中的情况'。也就是说,你有很好的URI。

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

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

PUT是幂等的,因此您基本上断言product-id引用的产品的标签存在。如果您多次发送此请求,则第一次获得201 Created,下次获得200 OK

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

如果介于两者之间且删除了该标记,则您的下一个put请求将重新创建该标记。这是你想要的吗?

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

如果您正在构建一个中等高级的并发系统,使用first-writer-wins语义,在单个服务器上运行,则可以立即停止阅读

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

HTTP PATCH的RFC说明了这一点:

  

但是,使用PATCH,随附的实体包含一组   说明资源当前如何驻留在   应修改原始服务器以生成新版本。 PATCH   方法影响Request-URI标识的资源,它也是   可能对其他资源产生副作用;即,新资源可能是   通过应用PATCH创建或修改现有的。

     

PATCH是既不安全也不是幂等,如[RFC2616],Section所定义   9.1。

我现在可能会停止把奇怪的想法放在脑海里。评论你是否希望我继续沿着这条路走一段时间;)。我只想说可以做更多的考虑。