仅针对聚合根更新RESTful资源

时间:2017-01-19 10:10:17

标签: 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"
}

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

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

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

关于该主题的更多背景

在一天结束时,有人可能会说像这样的API并非完全RESTful,因为我不应该期望使用PATCH动词删除某些特定产品的功能,但{ {1}}:DELETE,与使用 DTO 修补产品相比,从客户的角度来看,更容易转换API使用情况。

1 个答案:

答案 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 callhttps://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