仅针对聚合根更新RESTful资源 [英] Updating RESTful resources against aggregate roots only

查看:210
本文介绍了仅针对聚合根更新RESTful资源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常我使用以下资源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 但是我认为功能是给定产品的一部分,因此,我更新哪些功能可能包含以下功能:

  PATCH / products / {id} 

{
features:{
add:[1,2,3 ]
}
}

另一方面,如果我想更新一些功能元数据我不会使用产品资源,但我会执行这样的请求:

  PATCH / products / features / {id} 

{
title:Test
}

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



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



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



关于该主题的更多背景



在一天结束时,一个可能会说像这样的API不是完全RESTful的,因为我不应该期望使用 PATCH 动词从某些给定产品中删除功能,但是 DELETE DELETE / products / {id} / features / {featureId} ,这比从客户端角度更容易转换API使用产品带有 DTO

解决方案

现在您的架构并不完全干净。在某种程度上,你实现了宁静的思维方式,但另一方面,像


  PATCH / products / {id} 

{
features:{
add:[1,2,3]
}
}




< blockquote>

  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:...
},
...
]
}

回答你的问题,如果按照我的建议以正确的方式正确实施,更新产品功能绝对没问题。






编辑:


关于/ products / features或/ product-features的内容,是否有
对此有何共识?你知道任何一个好的来源,确保它只是一个品味的


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


关于修补时的添加内容,这是我发现
表示我正在添加,更新或删除给定$中的功能的最简单方法b $ b产品。事实上,它是一个DTO


如果你想对集合使用一些动作,那么就有一个标准。只需看看最佳做法批量更新REST Api调用中的集合
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:添加,路径:/ features / 0,value:3
}




BTW,请注意您在我的问题中没有回答核心问题。


由于所有内容都可视为子资源,如果产品的功能(作为集合)是产品的属性,并且它被视为启用POST的子资源,我也不会发现任何冲突。如果一个人发现它不安全,那么你可以仅在子资源上将其切割为操作



此外,在此文章作者批准了用PATCH更新子资源的方法,简化了过程(整篇文章有点争议,但并不是我们感兴趣的事情)


另一个解决方案是公开资源的属性你想
make editable,并使用PUT方法发送更新的值。在下面的
示例中,公开了用户123的电子邮件属性:

  PUT / users / 123 / email 

new.email@example.org

虽然它清楚了,看起来这是一个很好的方式来决定公开什么以及什么不公开,这个解决方案在你的API中引入了很多
的复杂性(控制器中的更多动作,路由
定义,文档等)。但是,它符合REST,并且是一个
不太糟糕的解决方案,但有一个更好的选择:PATCH



Usually I architect RESTful APIs using the following resource URI scheme:

POST /products
PATCH /products/{id}
GET /products
GET /products/{id}
DELETE /products/{id}

Products may also contain product features. When I want to get some product's features, I would perform a GET /products/{id}/features.

BTW, if I want to add new features to a given product, usually I don't provide a resource URI like this: PATCH /products/{id}/features but I consider that features are part of a given product, thus, I update which features might contain a feature as follows:

PATCH /products/{id}

{
    "features": {
         "add": [1, 2, 3]
    }
}

In the other hand, if I want to update some feature metadata I wouldn't use the product resource but I would perform a request like this:

PATCH /products/features/{id}

{
    title: "Test"
}

In my case, product features are unrelated to a particular product, but they can be associated to many products.

Ideally, I should update which features own a given product issuing a PATCH request to /products/{id}/features, BTW it overcomplicates the server API because you need to cover all entity's aggregates separately.

My concern is if it's fine to consider that some given aggregate root's associations are updatable as part of the entity itself.

More background on the topic

At the end of the day, one might say that an API like this isn't fully RESTful, because I shouldn't expect to remove features from some given product using PATCH verb but DELETE: DELETE /products/{id}/features/{featureId}, which turns the API usage from the client point of view easier than patching the product with a DTO.

解决方案

Right now your architecture isn't perfectly clean. In part, you implement restful way of thinking, but on the other hand, things like

PATCH /products/{id}

{
    "features": {
         "add": [1, 2, 3]
    }
}

or

PATCH /products/features/{id}

{
    title: "Test"
}

are unintuitive.

For the first example, I would recommend

PATCH /products/{id}

{
    "features": [
        {
            "id": 1
        },
        {
            "id": 2
        },
        {
            "id": 3
        },
        {
            "id": 4
        }
    ]
}

where you provide all features for this product. You can't just define your own element add, which adds given features to the product. Structure of the updating resource should be comparable to structure you get with GET /products/{id} (I guess you don't get add attribute, do you?).

For the second one, your url should be sth like /product-features/{feature_id} or just /features/{feature_id}. Don't break the pattern /products/{product_id} with /products/features/{feature_id}. Why should you think this way? It's logical - when you GET /products, you don't get resource with list of all features

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

but instead of, a list of all products

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

Answering to your question, if you implement it properly as I suggested in a restful way, updating product's features is absolutely okay this method.


Edit:

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?

I think this is misleading. I would expect to get all features in all products rather than get all possible features. But, to be honest, it’s hard to find any source talking directly about this problem, but there is a bunch of articles where people don’t try to create nested resources like /products/features, but do this 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

If you want to use some actions on collections, there is a standard for it. Just take a look at Best practice to batch update a collection in a REST Api call and https://tools.ietf.org/html/rfc6902#appendix-A.2. Instead of

PATCH /products/{id}

{
    "features": {
         "add": [1, 2, 3]
    }
}

you will send

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.

As everything can be considered as sub-resource, I don't see any conflict if product's features, as a collection, is an attribute of the product and also it's considered as sub-resource to enable POST for example. If one's find it not safe, then you can cut it to operate only on sub-resource.

Moreover, in this article author approved the way of updating sub-resources with PATCH do simplify the process (the whole article is a little bit controversial but it's not over the thing we are interested)

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

new.email@example.org

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

这篇关于仅针对聚合根更新RESTful资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆