通常我使用以下资源URI方案构建RESTful API:
POST /products
PATCH /products/{id}
GET /products
GET /products/{id}
DELETE /products/{id}
产品还可能包含产品功能。当我想获得某些产品的功能时,我会执行GET /products/{id}/features
。
顺便说一句,如果我想为给定的产品添加新功能,通常我不提供这样的资源URI:PATCH /products/{id}/features
但我认为features
是给定产品的一部分因此,我更新了哪些功能可能包含如下功能:
PATCH /products/{id}
{
"features": {
"add": [1, 2, 3]
}
}
另一方面,如果我想更新某些功能元数据,我不会使用产品资源,但我会执行这样的请求:
PATCH /products/features/{id}
{
title: "Test"
}
就我而言,产品功能与特定产品无关,但它们可以与许多产品相关联。
理想情况下,我应该更新哪些功能拥有向PATCH
发出/products/{id}/features
请求的给定产品,BTW它会使服务器API过于复杂,因为您需要单独覆盖所有实体的聚合。 / p>
我担心的是,考虑到某些给定的聚合根关联可以作为实体本身的一部分更新,这是否可以。
在一天结束时,有人可能会说像这样的API并非完全RESTful,因为我不应该期望使用PATCH
动词删除某些特定产品的功能,但{ {1}}:DELETE
,与使用 DTO 修补产品相比,从客户的角度来看,更容易转换API使用情况。
答案 0 :(得分:2)
现在你的建筑并不是很完美。在某种程度上,你实现了宁静的思维方式,但另一方面,像
这样的事情PATCH /products/{id} { "features": { "add": [1, 2, 3] } }
或
PATCH /products/features/{id} { title: "Test" }
不直观。
对于第一个例子,我建议
PATCH /products/{id}
{
"features": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
},
{
"id": 4
}
]
}
您为此产品提供所有功能。您不能只定义自己的元素add
,它会为产品添加特定功能。更新资源的结构应该与GET /products/{id}
得到的结构相当(我猜你没有获得add
属性,是吗?)。
对于第二个,您的网址应该像/product-features/{feature_id}
或/features/{feature_id}
。不要将模式/products/{product_id}
与/products/features/{feature_id}
分开。你为什么要这么想?这是合乎逻辑的 - 当你GET /products
时,你没有获得包含所有功能列表的资源
{
...
"features": [
{
"id": 1
},
...
]
...
}
而不是所有产品的清单
{
[
{
....
"id": 1,
"features": ...
},
...
]
}
回答你的问题,如果按照我的建议以正确的方式正确实施,更新产品功能绝对没问题。
修改强>
关于/ products / features或/ product-features的东西,有 对此有何共识?你知道任何好的来源,以确保它是 不仅仅是品味问题?
我认为这是误导。我希望获得所有产品的所有功能,而不是获得所有可能的功能。但是,说实话,很难找到任何直接谈论这个问题的消息来源,但有一些文章,人们不会尝试创建/ products / features等嵌套资源,但这样做separately。
关于修补时添加的东西,这是我找到的最简单的方法 表示我正在添加,更新或删除给定的功能 产品。事实上,它是一个DTO
如果要对集合使用某些操作,则有一个标准。只需看看Best practice to batch update a collection in a REST Api call 和https://tools.ietf.org/html/rfc6902#appendix-A.2。而不是
PATCH /products/{id}
{
"features": {
"add": [1, 2, 3]
}
}
你会发送
PATCH /products/{id}
{
"op": add, "path": "/features/0", "value": 1,
"op": add, "path": "/features/0", "value": 2,
"op": add, "path": "/features/0", "value": 3
}
顺便说一句,请注意你在我的问题中没有回答核心问题。
作为everything can be considered as sub-resource,如果产品的功能(作为集合)是产品的属性,并且它被视为启用POST的子资源,我认为没有任何冲突。如果一个人发现它不安全,那么你只能在子资源上cut it to operate。
此外,在这位article作者批准用PATCH更新子资源的方法确实简化了整个过程(整篇文章有点争议,但并不是我们感兴趣的事情)
另一种解决方案是公开您想要的资源属性 make editable,并使用PUT方法发送更新的值。在里面 在下面的示例中,公开了用户123的电子邮件属性:
PUT /users/123/email new.email@example.org
虽然它使事情变得清晰,但它看起来是一个很好的决定方式 这个解决方案引入了很多内容,揭示了什么以及不暴露什么 API的复杂性(控制器中的更多操作,路由 定义,文档等)。但是,它符合REST,并且 不是那么糟糕的解决方案,但有一个更好的选择:PATCH