仅针对聚合根更新 RESTful 资源

2023-12-09

通常我使用以下资源 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顺便说一句,它使服务器 API 过于复杂,因为您需要单独覆盖所有实体的聚合。

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

有关该主题的更多背景信息

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


现在你的架构并不完全干净。一方面,你实施了宁静的思维方式,但另一方面,诸如此类的事情

PATCH /products/{id}

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

or

PATCH /products/features/{id}

{
    title: "Test"
}

不直观。

对于第一个例子,我建议

PATCH /products/{id}

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

你在哪里提供all该产品的功能。你不能只定义你自己的元素add,它将给定的功能添加到产品中。更新资源的结构应该与您获得的结构相当GET /products/{id}(我猜你没明白add属性,你是吗?)。

对于第二个,你的网址应该是这样的/product-features/{feature_id}要不就/features/{feature_id}。不要打破模式/products/{product_id} with /products/features/{feature_id}。为什么你要这样想?这是合乎逻辑的——当你GET /products,您不会获得包含所有功能列表的资源

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

但不是所有产品的列表

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

回答你的问题,如果你按照我的建议以一种轻松的方式正确实施它,那么更新产品的功能绝对可以用这种方法。


Edit:

关于 /products/features 或 /product-features 的东西,有吗 对此有何共识?你知道有什么好的来源可以确保它是 不仅仅是品味问题?

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

关于修补时添加的东西,这是我发现的最简单的方法 表达我正在添加、更新或删除给定的功能 产品。其实就是一个DTO

如果您想对集合使用某些操作,则有一个标准。看看吧在 REST Api 调用中批量更新集合的最佳实践 and https://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
}

顺便说一句,请注意,您没有回答我问题中的核心问题。

As 一切都可以被视为子资源,如果产品的功能作为一个集合,是产品的一个属性,并且它被视为启用 POST 的子资源,那么我没有看到任何冲突。如果有人发现它不安全,那么你可以剪开即可操作仅在子资源上。

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

另一个解决方案是公开您想要的资源的属性 使其可编辑,并使用 PUT 方法发送更新的值。在里面 下面的示例,暴露了用户 123 的电子邮件属性:

PUT /users/123/email
 
[email protected]

虽然它让事情变得清晰,而且看起来是一个很好的决定方式 暴露什么和不暴露什么,这个解决方案介绍了很多 API 的复杂性(控制器中的更多操作、路由 定义、文档等)。然而,它符合 REST 标准,并且 不错的解决方案,但有一个更好的选择:PATCH

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅针对聚合根更新 RESTful 资源 的相关文章

随机推荐

  • #if __IPHONE_4_0 在 iPad 上运行吗?

    此检查在 iPad 和 iPhone 上都有效吗 我想我只是对在 iPad 上使用 iPhone 一词感到困惑 我还需要检查 iPad OS 版本吗 或者宏是否指的是一般 iOS 版本 if IPHONE 4 0 Do stuff elif
  • dplyr 中的 mutate_each / summarise_each:如何选择某些列并为变异列提供新名称?

    我有点困惑dplyr verb mutate each 使用基本的方法非常简单mutate将一列数据转换为 z 分数 并在 data frame 中创建一个新列 此处名称为z score data newDF lt DF gt select
  • 如何在机器人框架中的小黄瓜式测试中指定句子中间的参数?

    使用 Robot Framework 我打算使用 Gherkin 风格的测试 因为它是 BDD ATDD 的通用语言 我可以指定这样的测试 Test Cases New alert Given there were no alerts so
  • C# 中标准 I/O 的非阻塞读取

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我想要一个来自控制台的非阻塞读取功能 我如何用 C 编写它 理查德 达顿有一个解
  • Android 将图像拖放到屏幕上?

    我正在帮助项目用户将图像从一个位置移动到屏幕上的另一个位置 我已经编写了一个示例代码来移动图像 但这里的问题是 如果我移动一个图像 相邻图像也会开始移动 这是示例代码 任何一个想法 主程序 java public class MainAct
  • 如何将 h5 文件转换为 tflite 文件?

    我正在尝试在 Android 上运行车牌检测 所以首先我找到这个教程 https medium com quangnhatnguyenle detect and recognize vehicles license plate with m
  • 编写分类栅格及其符号系统

    我已经对很多栅格进行了分类 我想用我定义的符号系统来编写它们 这是我正在处理的栅格类型 library raster library rasterVis r lt raster nrow 10 ncol 10 r 1 r 51 100 3
  • 如何仅打印(调整后的)回归模型的 R 平方?

    我是 R 初学者 我有一个关于空气污染的数据集 这些列是站点 测量浓度和可能影响浓度的 80 个变量 v1 v80 我想用我自己的代码创建一个基于 R squared adj 的前向逐步回归模型 所以我不想使用诸如 step 或 regsu
  • 将 char 指针从 C# 传递到 C++ [重复]

    这个问题在这里已经有答案了 可能的重复 将 char 指针从 C 传递到 C 函数 我有这样的问题 我有一个具有以下签名的 C 函数 int myfunction char Buffer int rotation 缓冲区参数必须用空格字符
  • Angular2 异常:尝试检测脱水检测器上的变化

    我遇到这个错误EXCEPTION Attempt to detect changes on a dehydrated detector 并在阅读了一些在线页面后 我不太清楚如何解决它或者因为它是 https github com angul
  • 将句子拆分为单词

    例如我有这样的句子 text word word w d word 我需要这样的数组 Array 0 gt word 1 gt word 2 gt w d 3 gt word 我对正则表达式很陌生 这是我尝试过的 function divi
  • 对象中所有属性的总和

    我有以下对象 speed 299 equipment 49 teleabb 49 additional 50 optional 299 我想将所有这些值相加并打印出来 如何对属性值求和 使用迭代对象属性for var in Use pars
  • EJB3.0 将句柄序列化为 Stateful Bean

    我正在尝试保留有状态 EJB3 0 bean 的远程句柄 该bean的接口定义为 Remote public interface Hello extends Serializable Handle getHandle void sayHel
  • 如何在 OpenCV 中进行逆 DFT [重复]

    这个问题在这里已经有答案了 我正在尝试在 C 中使用 OpenCV 实现逆 DFT 我在 docs opencv org 下载了完整的 dft 示例 只需调整几行即可反转 我的DFT代码是这样的 Mat DFT const char fil
  • iOS 8:如果没有情节提要,自动旋转将无法工作

    所以我试图启动一个没有故事板的项目 但我似乎无法弄清楚为什么 UIWindow 没有将自动旋转命令传递给根视图控制器 有了故事板 自动旋转就可以了 如果我以编程方式创建窗口 自动旋转将不起作用 这是我在应用程序委托中实例化窗口的方式 win
  • 如何通过 Java 使用 XPath 和 Selenium WebDriver 单击 SVG 元素

    我有一个SVG具有一些矩形元素的对象 使用geckodriver 我正在尝试单击主要内容之一SVG目的 但是 使用 xpath checker 我无法检测到正确的xpath对于相同的 到目前为止 我能够深入了解xpath upto id a
  • 角度 ui.bootstrap.carousel 从 $scope 调用 next()/prev()

    如何从幻灯片访问轮播的 next prev 方法 我正在尝试连接到 hm swipe left right 但我似乎没有正确的 scope
  • 为什么使用 MSXML v3.0 可以解析 XML 文档,而 MSXML v6.0 却不行

    因此 我正在开发一个项目 根据每个来源的特征 使用许多不同的方法从互联网上的许多不同来源抓取和收集数据 最近添加的是一个网络API返回以下内容的调用XML作为回应
  • 当我选择文本字段时,键盘会在其上方移动

    当我选择一个文本字段时 将显示键盘 但键盘隐藏我选择的文本字段 有人有解决办法吗 Scaffold resizeToAvoidBottomInset true body SingleChildScrollView child Contain
  • 仅针对聚合根更新 RESTful 资源

    通常我使用以下资源 URI 方案来构建 RESTful API POST products PATCH products id GET products GET products id DELETE products id 产品还可能含有产