json - 仅针对聚合根更新 RESTful 资源

标签 json web-services rest http restful-architecture

通常我使用以下资源 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"
}

就我而言,产品功能与特定产品无关,但它们可以与许多产品相关联。

理想情况下,我应该更新哪些功能拥有给定的产品,向 /products/{id}/features 发出 PATCH 请求,顺便说一句,它使服务器 API 过于复杂,因为您需要分别覆盖所有实体的聚合。

我关心的是,考虑某些给定聚合根的关联是否可以作为实体本身的一部分进行更新。

有关该主题的更多背景

归根结底,有人可能会说这样的 API 并不完全是 RESTful,因为我不应该期望使用 PATCH 动词从某些给定产品中删除功能,但是 DELETE:DELETE/products/{id}/features/{featureId},这比使用 DTO 修补产品更容易从客户端角度使用 API 。

最佳答案

现在您的架构并不完全干净。一方面,您实现了 Restful 思维方式,但另一方面,诸如

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/features/{feature_id} 破坏 /products/{product_id} 模式。为什么你要这样想?这是合乎逻辑的 - 当您 GET/products 时,您不会获得包含所有功能列表的资源

{
    ...
    "features": [
        {
             "id": 1
        },
        ...
    ]
    ...
}

而是所有产品的列表

{
     [
          {
               ....
               "id": 1,
               "features": ...
          },
          ...
     ]
}

回答你的问题,如果你按照我的建议以一种轻松的方式正确实现它,更新产品的功能是绝对没问题的。


编辑:

About the thing of /products/features or /product-features, is there any consensus on this? Do you know any good source to ensure that it's not just a matter of taste?

我认为这是误导。我希望获得所有产品的所有功能,而不是获得所有可能的功能。但是,说实话,很难找到任何直接讨论这个问题的来源,但是有很多文章,人们没有尝试创建像/products/features 这样的嵌套资源,而是这样做 separately .

About the thing of add when patching, it's the easiest way I've found to express that I'm adding, updating or removing features from a given product. In fact, it's a DTO

如果您想对集合使用某些操作,则有一个标准。看看Best practice to batch update a collection in a REST Api callhttps://www.rfc-editor.org/rfc/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
}

BTW, note that you didn't answer the core issue in my question.

everything can be considered as sub-resource ,如果产品的功能作为一个集合,是产品的一个属性,并且它被视为启用 POST 的子资源,那么我没有看到任何冲突。如果有人发现它不安全,那么您可以 cut it to operate仅在子资源上。

此外,在这个article作者认可使用PATCH更新子资源的方式确实简化了流程(整篇文章有点争议,但还没有结束我们感兴趣的事情)

Another solution is to expose the resource’s properties you want to make editable, and use the PUT method to send an updated value. In the example below, the email property of user 123 is exposed:

PUT /users/123/email
 
<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="82ece7f5ace7efe3ebeec2e7fae3eff2eee7acedf0e5" rel="noreferrer noopener nofollow">[email protected]</a>

While it makes things clear, and it looks like a nice way to decide what to expose and what not to expose, this solution introduces a lot of complexity into your API (more actions in the controllers, routing definition, documentation, etc.). However, it is REST compliant, and a not-so-bad solution, but there is a better alternative: PATCH

关于json - 仅针对聚合根更新 RESTful 资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41739067/

相关文章:

java - 将字符串转换为 jsonobject 时出现异常

java - Micronaut Controller 如何确定其基本 URL

Python 异步网络服务调用

c# - 带参数的 ASP.NET Web Api HttpClient.GetAsync

python - Django REST Framework - 类 UserSerializer 缺少 "Meta.model"属性

javascript - 我想使用位置功能向 #cart-total-remove 添加一个类,我尝试了很多方法但没有成功

javascript - 当我更改 http.jsonp() URL 时,JSON 数据未显示

json - PowerShell ConvertFrom-Json 未将 JSON 列表转换为 Json 对象

php - 如何在 Cakephp 中发起 https post 请求

ruby-on-rails - rails respond_to 和各种形式的 html 响应