优秀的 REST API 设计指南

2020-07-29 06:14:50 +08:00
 KalaSearch

这是一篇会长期更新的文章

什么样的 API 设计能被称为优秀当然是一个非常主观的标准,但是还是有一些客观可考量 API 质量的数据,比如

  1. 接了你设计的 API 的前端给好评的比例是多少,还是边接边骂
  2. 如果你的 API 本身就是你的产品的话(比如 Stripe,Algolia 或者 Github 等等),你的用户会对你的 API 好评吗
  3. API 是不是一读即可以清晰地知道,对应接口是做什么的。换句话说,接入 API 时需要的交流时间成本有多高

不管是前端程序员还是后端程序员,都少不了跟 API 打交道。后端需要把 API 设计和实现出来,而前端程序员需要把界面逻辑和 API 接起来,因此对于 REST 的设计规则有一些基本了解,不管你是前端还是后端,都会有很大帮助。

之前在厂里设计了一些还算被广泛使用的 API, 因此我写了这篇文章,结合之前的经验总结了一些要点。希望作为一个参考,可以帮助大家

文章请戳 => 优秀的 REST API 设计指南

当然我想要说明的是,设计 API 在一定范围内是有规律可循的,但是太过抠细节则会陷入无穷无尽地“宗教版”争论中,所以请大家理论讨论。

你们设计 API 的时候有些什么原则?有哪些好的规范和经验可以介绍和分享给大家?欢迎告诉我,我会加到文章中

26864 次点击
所在节点    程序员
98 条回复
iplayio2019
2020-08-12 00:54:23 +08:00
@est /user/login 这种可以抽象成 session 资源,restful 很强调“资源”概念,POST /api/sessions,登录就是创建 session 。
注销登录 DELETE /api/sessions/me

取消订单本身就是状态更新,PATCH /api/orders/{orderID}
<status>:<取消状态的值>
est
2020-08-12 10:08:43 +08:00
@iplayio2019

那么问题来了

1. 一次登入多个站点的 SSO 怎么设计 URL
2. 订单拆分、合并操作如何表达?
3. 上面的同学提到的,批量操作如何写{orderID} ?
lovedebug
2020-08-12 10:15:28 +08:00
@est
RESTful 规范描述的是资源,对于非资源的情形一般需要自定义 action,这一方面大厂已经做了详细的设计,落实到具体设计就根据各自情况做了
比如你的描述提到的
1, 一般写成 POST /users/${userId}/login?type=sso 或者 login?user=xxx & type=xxx
2,一般会写成 POST /orders/${orderId}/$spilit 或者 POST /orders/${orderId}/$merge {ids:[]}
3 一般写成 POST /items/$batchUpdate {ids:[]}
est
2020-08-12 10:34:00 +08:00
@lovedebug 其实你 2 和 3 已经是另外一种风格的 URL 设计了。。。还不如干脆一条路走到黑全按照这种风格来设计

1. POST /user/login
2. POST /order/split POST /order/merge
3. POST /item/batchUpdate

多干净统一。


RESTful 就是被 UNIX 那种「所有东西都是文件」思想毒害的。遇到完全不像文件或者资源的东西,瞎搞。
lovedebug
2020-08-12 10:46:29 +08:00
@est 对于自定义 action,RESTful 本来就没有统一,自定义 API 风格各个团队根据自己需要定义就可以
两种方案
1. 将资源 uuid 描述在 URL 中
2. 将资源 uuid 描述在 body 中
我们两人上面的就是这两种方案的体验,没有好和坏,只看对于 API 使用者的可读性。
微软和谷歌,github 对于自定义 action 也是分别有自己的实现
no1xsyzy
2020-08-12 13:34:32 +08:00
@est #84 问题不在于 “一切皆文件”,而在于纯远端操作。
文件是对于 “可读可写” 的抽象。举上述你提到的例子:
1. 登录是一个状态,SSO 是一个多服务端共享的状态,可读可写,而且读写经过客户端传递,与文件这一抽象完美契合不成问题。
sub_site 302 到 //sso_host/user/login?to=sub_site/user/login
然后由 sso_host 确定后 302 传递 token //sub_site/user/login?with_token=~~token~~
类比: $ cat sso/token | authorize sub_site

2. 拆分合并的核心在于它是个纯远端操作。一般来说在 Unix 下拆分文件,不出意外是 head|tail 或者 awk/sed 之类,或者对特定的文件类型也是专门的提取器而不是单独的拆分装置。然而无法保证拆分的准确性。那么显然,正确的操作应当是写一个专门的脚本完成这件事 —— 类比过来,就是新谓词。
SPLITORDER /orders/<orderId>,请求体发送拆分准则之类的,返回 200 内容是拆分结果。
类比: $ split_order "site/orders/${orderId}" [--options ...]
site/orders/a site/orders/b site/orders/c

3. 批量操作可以借用 glob,也可以是单独谓词。后者不必说,前者比如:
PATCH /orders/{a,b,c}
Content-Type: application/json

{"coupon": "foobar"}
est
2020-08-12 14:58:13 +08:00
> SPLITORDER /orders/<orderId>,请求体发送拆分准则之类的,返回 200 内容是拆分结果。

对对对。。就是喜欢 RESTful 原教旨主义者这种一本正经发明 1000 个新词的想法。。。。

反正我对 http 的 verb 就认同 2 个,读是 GET, 写就是 POST 。你们觉得 1000 个新词最血统纯正我也没办法。。。。
est
2020-08-12 14:59:29 +08:00
@lovedebug 我也差不多是这个观点。RESTful 其实没必要完全照搬。取其精华,去其糟粕。团队内部统一认识就行。
ChristopherWu
2020-08-12 17:25:26 +08:00
@est
@no1xsyzy
@lovedebug

RESTFul 是不是还有一个问题就是,强绑定于 HTTP ?
假如我的业务除了 HTTP 接口给外部团队使用外,还要提供二进制协议的接口给内部团队使用,那么 Restful 就不通用了。
相对来说,使用 RPC 风格的协议,可以统一 API,不管什么,code,message,data 三个字段封装起来就是业务层,其他 code 是协议层的事情。
brickxu
2020-08-12 18:44:05 +08:00
你这涉猎够广的,另外一个贴子里还在分析 NoSQL,这边直接换到 API 设计了,然后全是 kala 搜索的域名。
no1xsyzy
2020-08-12 19:27:24 +08:00
@est #87 奇妙,我根本不是原教旨主义者
我跟你讲,原教旨主义者的看法是,拆分订单就是删除旧订单,然后建两个新的。
至于批处理,原教旨主义者认为就应该发 100 个请求,服务器被撑爆就应该扩容、增技术 balabala 。

建新谓词是传播主义者的一支,把 RESTful 当 RPC 用。
est
2020-08-13 10:29:43 +08:00
> 我跟你讲,原教旨主义者的看法是,拆分订单就是删除旧订单,然后建两个新的。
> 至于批处理,原教旨主义者认为就应该发 100 个请求,服务器被撑爆就应该扩容、增技术 balabala 。
> 建新谓词是传播主义者的一支,把 RESTful 当 RPC 用。


我石化了。。。。
AlbertChen
2020-09-18 09:38:45 +08:00
@gnozix 返回 JSON, 里边包含下载链接啊
goodboy95
2020-09-18 10:05:46 +08:00
反正我从来不设计 RESTapi,我只设计 api,只是长的有那么点像 REST
fhsan
2020-09-18 10:40:05 +08:00
怎么来说呢,内部自己的小项目都是 rest,对外的一律 post,因为你不知道对方有啥骚操作
kokodayo
2020-09-18 11:55:52 +08:00
@lolizeppelin REST 是,RESTful 就还好啦,毕竟部分思想还是好用的,而且 ful 到什么程度也是开发者自己说了算→_→
icew4y
2020-09-18 16:44:53 +08:00
restful 就是一残废
abersheeran
2021-03-09 12:22:47 +08:00
@fhsan 哈哈哈哈哈哈哈哈哈,对。我写的一个 RPC 框架,全都是 POST,具体内容全部走 Body 。大家都很满意(指服务端开发和客户端开发)。

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

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

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

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

© 2021 V2EX