作为一个 CRUD boy,最近想要努力将 RESTful 付诸实践。 但是有一个问题一直困扰着我:
修改数据该选用哪个 verb ? PUT 、POST 或是 PATCH ?
从语意来说,POST 是新增,PUT 是修改,PATCH 是部分修改。 从幂等性来说,POST 是非幂等的,而 PUT 和 PATCH 是幂等的。
现在我有两个问题:
1
yyfearth 2020-06-13 03:05:26 +08:00 1
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 功能 部分修改 |
2
askfermi 2020-06-13 03:10:03 +08:00 1
PATCH 应该是不必幂等的。
"A PATCH is not necessarily idempotent, although it can be." ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH |
3
jadec0der 2020-06-13 04:29:10 +08:00 1
incr field 具体是什么操作呢?
如果非要幂等的话可以考虑先 POST 一个 transaction,然后用 PUT/PATCH 把 transaction 状态改成确认。当然我觉得这就太教条了。 |
5
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 { ......... } 保存更改 ``` |