Rest 使用HTTP PUT更新嵌套资源的适当方式是什么?

Rest 使用HTTP PUT更新嵌套资源的适当方式是什么?,rest,webapi,http-put,Rest,Webapi,Http Put,我和同事正在讨论如何正确实现具有嵌套资源的HTTP PUT请求 示例情况:每个用户可以有多个地址,这些地址可以更新、删除或添加。我们试图最小化API的表面,并在单个事务中执行大多数操作,因此理想情况下,单个PUT端点应该处理所有这些操作 开发者1建议采用这种方法: PUT/users/1 { "fullName": "John Doe", "addresses": [ { "street"

我和同事正在讨论如何正确实现具有嵌套资源的HTTP PUT请求

示例情况:每个用户可以有多个地址,这些地址可以更新、删除或添加。我们试图最小化API的表面,并在单个事务中执行大多数操作,因此理想情况下,单个PUT端点应该处理所有这些操作

开发者1建议采用这种方法: PUT/users/1

{
  "fullName": "John Doe",
  "addresses": [
    {
      "street": "street1",
      "zipCode": "15000"
    },
    {
      "street": "street2",
      "zipCode": "15200"
    }
  ]
}
{
  "fullName": "John Doe",
  "addresses": [
    {
      "id": 5,
      "street": "street1",
      "zipCode": "15000"
    },
    {
      "street": "street2",
      "zipCode": "15200"
    }
  ]
}
在本例中,当前在DB中的所有用户现有地址都将被删除并替换为这两个提供的地址——“street1”和“street2”。如果为addresses属性提供的值是空数组,例如
“addresses::[]
-将从数据库中删除所有用户的地址。此外,禁止将地址设置为null:
“地址”:null
,只能提供空数组或带有项的数组

开发者2建议采用这种方法: PUT/users/1

{
  "fullName": "John Doe",
  "addresses": [
    {
      "street": "street1",
      "zipCode": "15000"
    },
    {
      "street": "street2",
      "zipCode": "15200"
    }
  ]
}
{
  "fullName": "John Doe",
  "addresses": [
    {
      "id": 5,
      "street": "street1",
      "zipCode": "15000"
    },
    {
      "street": "street2",
      "zipCode": "15200"
    }
  ]
}
注意-第一个地址对象中有
“id”:5
。在本例中,提供了id为5的地址-这将导致id为5的现有地址的更新。此外,还有一个没有指定Id的地址。这将创建一个新用户的地址(我指的是数据库中具有新Id的新地址记录)。最后,将从数据库中删除所有当前存在的用户地址(id=5的地址除外)。总而言之,这种方法允许前端开发人员指定是否应更新现有实体,或者是否应创建具有新Id的新地址

老实说,我不知道客户端应用程序是否应该负责指定是否应该更新或创建地址。第一个示例总是重新创建用户的地址

如果该地址还有一个上传的文件,则可以(使用示例2)将该上传的文件保留在数据库中,并仅更新zipCode(开发者1的示例不允许这样做),始终创建一个新地址,因此链接到该地址的任何先前上传的文件也将被“级联”删除

我们也可以选择使用HTTP DELETE或HTTP PATCH端点来删除或修改用户的地址,但如前所述,我们正尝试使用尽可能少的端点,并使用单个事务来执行大多数与db相关的操作


我想知道您对嵌套资源是否应该用ID标识,以及这两种方法是否足够好,或者在另一方面是否存在根本性缺陷/违反了某些REST API标准的看法。

第二个例子是不可理解的。如果只想创建一个rest端点,则必须在JSON级别添加命令。没有人强制要求JSON结构是纯数据。允许它包含多个命令,每个命令都有一个JSON结构,例如要添加或更新的命令。谢谢@Robert,这似乎是一个有趣的方法。{“全名”:“约翰·多伊”,“地址”:[{“id”:5,“街道”:“街道1”,“zipCode”:“15000”,“命令”:“更新”},{“id”:6,“街道”:“街道2”,“zipCode”:“15200”,“命令”:“删除”},{//无需在此处指定id“街道”:“街道3”,“zipCode”:“15300”,“command:“add”}//数据库中其他用户已经存在的地址保持不变]}