如何在WebApi Core中设计多个Patch请求

7
我想知道在WebApi .Net Core中设计多个资源更新的最佳方法是什么。
例如,我想为“用户”资源启用以下功能:
- 更新用户密码 - 更新用户角色 - 更新用户详细信息(例如名字,姓氏等)
根据REST教程和文章,我了解到需要使用PATCH方法来更新部分资源。
我们在团队中进行了一些讨论,并对这两个选项感到困惑:
选项1
为不同操作实现多个PATCH路由:
- PATCH /api/users/{id}/password - PATCH /api/users/{id}/role - PATCH /api/users/{id}/details
选项2
仅为整个资源实现单个PATCH操作。用户将发送application/json-patch+json以进行部分更新。
- PATCH /api/users/id (接受JsonPatchDocument参数)
我尝试查找RESTful路由命名的最佳实践,大多数只涵盖简单的CRUD活动或嵌套资源。
对于这种多个更新操作,我想知道命名路由的最佳实践是什么?或者需要深入学习的相关术语是什么?谢谢。

1
请注意,每个PATCH请求只有一个路由/方法可以更好地进行授权控制。您可以使用这种方法为每个方法添加AuthorizeAttribute注释,以确保只有经过授权的用户才能更新您想要更新的字段(例如,只有管理员被允许更新用户角色,或者通常情况下:只有<其他用户组>被允许更新<字段>)。 - user8574318
1
我认为最好的方法是使用选项2的PUT。对于我来说,PATCH方法是你应该与OData或类似的东西一起使用的。 - S. Nadezhnyy
毫无疑问,选择 Option 2。此外,可以在这里看到它是如何实现的。 - Roman Marusyk
1个回答

3

PATCH请求用于更新单个资源的部分内容,即仅更换特定子集的资源字段。其语义最好描述为“根据我的更改请求,请更改由URL标识的资源”。

  • PATCH请求通常应用于单个资源,因为对整个集合进行修补是具有挑战性的
  • PATCH请求通常不够健壮以应对资源实例不存在的情况
  • 成功的PATCH请求,服务器将根据有效负载中的更改请求更新URL寻址的资源的一部分
  • 成功的PATCH请求通常会生成200204(如果返回已更新或未更新内容的更新资源)

注意: 由于正确地实现PATCH有点棘手,我强烈建议每个端点选择并且只选择以下模式之一。按优先级:

  1. 尽可能使用完整对象使用PUT更新资源(即根本不要使用PATCH)。
  2. 尽可能使用部分对象使用PATCH只更新资源的部分。(这基本上是JSON Merge Patch,一种特殊的媒体类型application/merge-patch+json,它是部分资源表示。)
  3. 使用PATCHJSON Patch,一种包括如何更改资源指令的专用媒体类型application/json-patch+json
  4. 如果请求不以媒体类型的语义定义的方式修改资源,则使用POST(并适当描述正在发生的事情)代替PATCH

选项1似乎设计不良,因为您将为每个属性拥有很多端点。

选项2遵循REST建议并在RFC 6902中指定。

您可以以下列方式实现它:

  • Delta (Microsoft ASP.NET WebAPI OData的一部分): 使用JSON时会出现一些数字问题。您还需要安装带有所有非平凡依赖项的软件包;
  • JSON Patch: 客户端必须按操作组织数据,并且请求的大小未经优化。
  • 使用Simple.HttpPatch可轻松应用部分更新。
  • 另一种SimplePatch实现

路由命名

  • 使用复数名词作为资源名称。不要混淆单数和复数名词。保持简单,对所有资源仅使用复数名词(users,而不是user)

  • 如果每个资源有两个基URL,则第一个URL是集合(列表)的URL,第二个URL是集合中特定元素的URL(/users/users/1)

  • 如果存在关系,请使用子资源。

/users/1/phones - 返回用户1的电话列表
/users/1/phones/1 - 返回用户1的电话#1

  • 不要在基URL中使用动词。使用HTTP请求方法GET, POST, PUT/PATCH, DELETE与两个基URL执行CRUD操作。关键在于开发人员可能不需要文档来了解API的行为。否则,您将拥有一个长URL列表,没有一致的模式,使得开发人员难以学习如何使用您的API.

  • 复杂的事情需要隐藏在后面。几乎每个API都有许多参数,您可以读取、更新、过滤并以任何其他方式使用它们。但是,所有这些参数不应显示在基地址中。最好在指向基地址的引用中指定参数。

GET /users/1234?firstName=Bill&PhoneNumber="1111"

另请参阅链接


1
只是补充一下,https://github.com/OmarMuscatello/SimplePatch 也是一个非常优秀的 Patch 库。 - user8574318

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接