HTTP PATCH 的问题

2020-06-13 00:05:13 +08:00
 acr0ss

作为一个 CRUD boy,最近想要努力将 RESTful 付诸实践。 但是有一个问题一直困扰着我:

修改数据该选用哪个 verb ? PUT 、POST 或是 PATCH ?

从语意来说,POST 是新增,PUT 是修改,PATCH 是部分修改。 从幂等性来说,POST 是非幂等的,而 PUT 和 PATCH 是幂等的。

现在我有两个问题

  1. 如果是 incr field 操作,PUT 和 PATCH 无法做到幂等,这种情况下各位老哥会如何抉择?
  2. PATCH 这个动词,实践中会使用吗?使用的多吗?
2751 次点击
所在节点    HTTP
6 条回复
yyfearth
2020-06-13 03:05:26 +08:00
inc field 这个操作本身不是幂等的
直接放到 PUT 和 PATCH method 都不合适

比如 /object/11111/count 需要 inc 操作
那么 PUT 和 PATCH 都应该是直接对 count 进行赋值 而不是 INC 的操作
而赋值是幂等的

如果非要支持 INC 操作 那么应该用 POST 比如 POST /object/11111/count/inc 或者 POST /object/11111?op=incCount 这样比较合适
PUT 一般对应 db 的 replace 功能 替换记录
PATCH 一般是 update 功能 部分修改
askfermi
2020-06-13 03:10:03 +08:00
PATCH 应该是不必幂等的。

"A PATCH is not necessarily idempotent, although it can be."

ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH
jadec0der
2020-06-13 04:29:10 +08:00
incr field 具体是什么操作呢?

如果非要幂等的话可以考虑先 POST 一个 transaction,然后用 PUT/PATCH 把 transaction 状态改成确认。当然我觉得这就太教条了。
acr0ss
2020-06-13 09:45:09 +08:00
@askfermi 这个文档写的很详细,也回答了我的问题,感谢!
crclz
2020-06-21 15:28:44 +08:00
https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#74-supported-methods

和前面 Mozilla 的问答一样,微软的文档指出
PATCH ; Apply a partial update to an object ; Is Idempotent:False


关于 patch 还有一点,就是 patch 一般是提交多个字段:

例如我有个资源(或者数据库表),叫“离校请求”,有(学生 id,离校时长、离校原因、是否同意)几个字段。
那么,很容易想到的 patch 的请求就是 PATCH /离校请求 /123,body 是{离校时长:10 小时,离校原因:看病}。然后服务端在判断的时候,如果传过来的哪个字段不为 null,那么就代表客户端想要更新这个字段。这就做到了节省代码行数(只需写一个接口)。 当然,如果想要让客户端有能力将某个字段置为 null,就约定一个悬空值。

在这个场景中,对于“教师同意或拒绝离校申请”的功能,这个功能不是单纯的修改某一字段的值,还可能会有副作用,例如修改另外一个表“User”的“是否允许离校”字段。对此,有的人可能会单独开一个接口,例如`/离校请求 /11/处理请求`。

其实同意或拒绝离校申请这种也可以包含到 patch 请求体里面。
PATCH /离校请求 /11 。body 的 schema 就变成是:{离校时长:string?,离校原因:string?, 是否同意: bool? }。

这样的好处是节省代码,并且接口整洁。

当然,不同用户对于字段的权限不同,在 controller 代码里面应该是这样的结构:
``` cs
if body.离校时长!=null {
if 当前用户有权限修改离校市场{
修改离校时常
}
}

if body.离校原因 != null {
.........
}

保存更改
```
acr0ss
2020-06-22 19:48:22 +08:00
@crclz 那实际运用中,PATCH 用的多吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/681127

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX