Skip to content

门泊吴船亦已谋

RESTful 接口设计经验总结

本文归纳了 RESTful 接口设计实践中的一些经验。

POST 和 PUT

参考资料

PUT 是幂等的,而 POST 不是。 幂等意味着多次相同 PUT 请求之后系统的状态跟一次 PUT 请求的结果相同。

这让我们容易联想到,POST 用于创建资源而 PUT 用于更新资源。 虽然实际项目中大部分情况下确实是这样,但是这个表述是不准确的。 在明确资源名的情况下使用 PUT 请求就可以直接创建该资源,而针对这个资源名的多次 PUT 请求也只会对这同一个资源进行操作,因此是符合幂等的。 因此更准确的表述应该是:POST 用于创建服务端负责分配资源名的资源,而 PUT 请求用于客户端分配或已知资源名的资源的创建和更新。

路径变量与请求参数

路径变量与请求参数是在 URL 中传递数据的两种方式。 它们的区别在于路径变量应当用于指定唯一的资源,而请求参数用于指定筛选资源的条件。

使用路径变量应当能够定位到明确的资源。 路径变量通常是 ID 或者唯一的资源名。 如果没有该资源我们就应该返回 404 错误。

而请求参数筛选到资源可以有多个,也可以没有。 请求参数一般用于筛选某些字段或进行分页。 对于找不到资源的情况我们返回一个空列表就可以了。

PATCH

参考资料 参考资料

PATCH 用于更新某个资源的部分数据,有别于 PUT 请求必须完整地更新整个资源。 但是需要注意一点,与 PUT 不同,PATCH 没有被要求是幂等的,也就是对同一个资源的相同 PATCH 多次请求可能会导致该资源不断变化。

PATCH was something I created for the initial HTTP/1.1 proposal because partial PUT is never RESTful. ;-) -- Roy Fielding

另外,PATCH 并不是设计来用于真正的 RESTful 接口。Roy Fielding(HTTP 规范的作者,也是 REST 的发起者)明确说明 PATCH 是用于 HTTP/1.1 的,因为 REST 接口中从来没有部分更新。 但是完整地更新整个资源显然会造成带宽的浪费,因此在实际项目中 PATCH 也时常被混合在 REST 中一起使用。

状态码

状态码实际上非常简单,并不难理解,因此在实际项目中我们就很容易疏忽大意,最后陷入一些误区。 这里介绍一些常见的问题。

常见的误区就是所有的请求成功都返回 200,但是实际上只有返回的 Response 为整个资源时才能使用 200。 而在 PUT、POST 和 DELETE 请求中我们往往不会返回完整的资源,更多的是直接 Response 为空,因此这个时候状态码应当为 204(No Content)。 在 POST 请求(或者用于创建资源的 PUT 请求)成功后,如果需要返回完整的新对象,那么我们应当返回 201(Created)。

不过这些状态码在实际项目中完全不够用,很多时候会自己根据业务与实现细节自己定义一整套新的状态码然后直接扔在 Response 里,还省得去啃 rfc 了。

登录

初学 REST 遇到一个非常操蛋的问题就是登录的接口怎么设计。 不过实际上确实也很操蛋,应当把登录抽象为创建临时的 token,然后 POST 请求拿到 token 即为登录成功。

控制命令

考虑这样一个业务需求:前端需要经过后端查询或改变一些嵌入式设备的运行状态。

比较阳间的思路是把每台设备都抽象成一个资源。 但是实际发现设备向后端暴露的接口非常简洁,基本直接就是对某个寄存器的读写,并且甲方对与前端的显示暂时没有更高的要求,那么这个时候如果我们还强行做抽象就会增加系统的复杂性。 于是我们考虑直接把控制命令抽象为资源,把寄存器的编号扔在它的属性里,极大幅度缩短了开发时间以及跟甲方扯皮的时间。 然而最后的结果是甲方非常开心并且强化了他们的蜜汁自信,把嵌入式那边一顿爆改(甚至直接换成了 json),并且要求前端对数据分类显示。 我的心中只有 mmp。 不过好在按照之前说的设计这部分逻辑就没什么代码,所以也能算不亏,并且甚至可能还避开了甲方的折磨(因为对寄存器操作的封装直接扔给甲方那边的嵌入式了),可以算小赚。

优秀实践

很多时候我们也可以去参考 GitHub REST API