优秀的 REST API 设计指南

KalaSearch 16天前 21

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

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

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

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

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

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

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

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

最新回复 (58)
  • 楼主 KalaSearch 12天前
    引用 2
    其它值得参考的文章:

    https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/

    https://hackernoon.com/restful-api-designing-guidelines-the-best-practices-60e1d954e7c9

    https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
  • abbycin 12天前
    引用 3
    我八股文写得特别好
  • baiyi 12天前
    引用 4
    我认为在设计过程中,需要考虑 HTTP 方法的幂等性。比如 Github 的 Star 操作,为什么是 PUT 而不是 POST,就是从幂等性方面考虑的
  • KallyDev 12天前
    引用 5
    补充一个微软在 GitHub 公开的规范,非常详细

    https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md
  • shijianit 12天前
    引用 6
    如果要接口全部加密,get 方式请求,不是会暴露出来 id 数据吗?
  • xuanbg 12天前
    引用 7
    修改密码和重置密码怎么设计?软删和硬删同时存在怎么办?
  • xuanbg 12天前
    引用 8
    @shijianit 所以 id 不要用自增
  • bsg1992 12天前
    引用 9
    这种只适合对外的 api 并且功能单一
    一个 ERP 查询几十个字段你用 get?
  • gnozix 12天前
    引用 10
    想问问下载接口应该怎么设计
  • gowk 12天前
    引用 11
    @bsg1992 人家说的是在卡拉搜索的业务背景下,设计优秀 API 的最佳实践,你非要拿 ERP 来杠,有意思么
  • nockyQ 12天前
    引用 12
    关于版本划分这一块,除了常见的 URI 版本控制之外还有其他两种。
    https://restfulapi.net/versioning/
    感觉楼主可以在这个基础上展开聊一聊。
  • lolizeppelin 12天前
    引用 13
    paypal api 和沙箱比微信支付漂亮太多了

    但是不妨碍 paypal 垃圾微信支付好用......
  • 楼主 KalaSearch 12天前
    引用 14
    @nockyQ 啊是的,stripe 用的是这种。感谢你的新信息
  • 楼主 KalaSearch 12天前
    引用 15
    @baiyi 感谢 <3
  • 楼主 KalaSearch 12天前
    引用 16
    @KallyDev 这个很赞,我之前也看过,谢谢提出来,我会加到文章里
  • 楼主 KalaSearch 12天前
    引用 17
    @shijianit id 应该默认认为已经暴露,藏不住。楼下说的用 uuid 是个好办法,不过不管怎么样不应该认为 id 可以隐藏起来达到安全的目的。(安全我懂得不多,更详细等楼下们讨论啦)
  • 楼主 KalaSearch 12天前
    引用 18
    @gnozix 能说说具体场景吗?文件下载?
  • wellsc 12天前
    引用 19
    restfool (逃
  • MrTreasure 12天前
    引用 20
    还是缺乏具体场景,文中的内容就是是属于 restful 的标准。但是对于难点没有很好的讲解,比如 restful 如何返回错误。区分 HTTP 错误以及业务错误
  • ZacksT 12天前
    引用 21
    你的 REST API 满足公司 /研发团队标准就是好的设计。接口标准可以帮助开发者规避(公司研发 /团队研发)遇见过的问题或可能遇到的问题,也可以让组内代码标准化,统一化。

    就拿一个简单的例子,一个分页查询的接口。其包含分页条件与不定量的查询条件。
    你可以通过 GET 方式请求,将参数定义在 url 上。也可以通过 POST 方式请求,将查询参数定义在 requestbody 里。
    第一个方式,在遇到查询条件复杂的情况下,会导致 url 过长。
    第二种方式,又会产生很多 VO 的定义。
    采用混搭又让前后端代码变得混乱。

    我个人认为,只要满足团队要求的 API,就是好的 API 。具体实现各有好处,看团队取舍了
  • 楼主 KalaSearch 12天前
    引用 22
    @ZacksT 感谢回复。是的,满足团队、客户需求就是好 API 。对于你说的参数定义的例子,GET + URL 参数挺好的,遵从 REST 语义



    @wellsc 不要淘气
  • bsg1992 12天前
    引用 23
    @gowk 我并没有杠,你说回复也印证了我上面说的 [适合对外的 api 并且功能单一] r
  • ibreaker 12天前
    引用 24
    小伙子很活跃啊,天天都能刷到你
  • lovedebug 12天前
    引用 25
    @ZacksT 分页 GET 查询一般只带 limit 和 page,少量支持投影和过滤,如果有带其他复杂的 query 条件,其实更应该走 POST search 自定义方法
  • ieiayaobb 12天前
    引用 26
    Get by Id 的比较明确,如果是 Get by name 这种,name 是唯一的怎么设计比较好?不想用 query 是因为不想在 name 不存在的时候返回空数组,而是希望也能和 Get by id 一样返回 404
  • xjchenhao 12天前
    引用 27
    修改密码和重置密码,逼死强迫症
  • xjchenhao 12天前
    引用 28
    @xuanbg 修改密码和重置密码,逼死强迫症
  • grzhan 12天前
    引用 29
    之前负责撰写公司的 API 规范,当时也参考了很多包括 Azure ( https://docs.microsoft.com/zh-cn/azure/architecture/best-practices/api-design )、Google Cloud ( https://cloud.google.com/apis/design/ )等公司的规范,大厂的标准往往更加规范,给人很多对于 API 设计上概念理解的启发。

    其中感觉最详细的大概是 Zalendo 的: https://opensource.zalando.com/restful-api-guidelines/ ,其中有非常多的实践是可以参考的,也像 RFC 一样规范了 MUST 、SHOULD 、MAY 的遵守分级。

    关于文中提到的 REST 表示一个动作,我们参考的更多是 ElasticSearch API 的做法,即将动词加上下划线前缀,作为 POST 方法进行服务,形如: http://cloud.sy/machine/xxxx/_restart

    关于这一块 Google API 是用冒号作为前缀的,但一些路由框架会占用冒号作为关键字,因此考虑使用下划线代替。
  • gnozix 12天前
    引用 30
    @KalaSearch 对前台展示的表格数据,以 excel 的格式进行下载;所以需要下载的比较多。感觉 REST 风格不太容易表示需要下载的资源
  • wshcdr 12天前
    引用 31
    值得看一下
  • Heanes 12天前
    引用 32
    同意 8 楼,系统内部交互可能还是“常规”的设计形式
  • lovedebug 12天前
    引用 33
    @grzhan 同负责撰写 API 规范,其实关于 list 操作的 filter 功能,在实际 API 设计中有些疑惑使用场景,因为大部分情况下使用一般的 query parameter 就可以解决。我的理解是一般的 query parameter 默认是 and 操作,缺乏 or 操作以及 range value 等功能,而 $filter 主要在 url 中描述若干参数复杂的逻辑运算,如果这么做用 POST 自定义动作不是更好吗?想听一下你的理解。
  • xuanbg 12天前
    引用 34
    @lovedebug 要是支持复杂的 or 和 and 条件组合,url 参数就丑的要死了……不信的可以看 kibana
  • szthanatos 12天前
    引用 35
    批量操作的实践为什么很少有人谈←_←
  • solee 12天前
    引用 36
    经过几年的实践,我们最后全部统一了用 POST,之前看过一篇亚马逊写的关于 Restful API 设计的改进,加入动词的描述,感觉更合理
  • lovedebug 12天前
    引用 37
    @szthanatos 微软规范有谈的
  • lovedebug 12天前
    引用 38
    @xuanbg 哈哈 跟业务场景有关,如果不想用万能 POST,可能只能在 url query 中支持一些 or 查询,客户在使用我们的 public api 时提出的
  • lovedebug 12天前
    引用 39
    @solee 自定义动词应该在已有的 RESTful 规范不满足时候才使用
  • Nolink 12天前
    引用 40
    收藏了,谢谢分享
  • ericls 12天前
    引用 41
    用现成的 query language 不好吗? 非要把 http headers 滥用成 query 还要自己定义 实现 维护……
  • Amit 12天前
    引用 42
    @xuanbg
    密码一般都是要做 hash 的,且不能暴露给前端,所以需要对这个字段单独修改,而不能放到完整信息中修改并返回,修改密码是在登录状态下,所以我会设计为 PUT /v1/users/{id}/password (管理员修改用户密码)或 PUT /v1/users/self/password (修改自己的密码),重置密码我理解为非登录状态下修改密码(不确定用户身份),所以我会设计为 PUT /v1/users/password,然后再 body 中提供用户名、验证码等信息。

    软删除也是删除,对应用来说如果删除了就是不存在的,应用中不应该能看到,软删除和物理删除同时存在是不合理的,这种情况应该设计一个状态字段区分,而不是使用逻辑删除。
  • xuanbg 12天前
    引用 43
    @Amit
    修改密码和重置密码我也是一样的处理。在复数形式的资源后面,有时候不但要加动词,还得加属性,以定位到更细一层的资源才行。

    我说的软删其实是禁用,只是为了理解方便。业务前端看不到了,也就没得用了。但元数据管理后端应该能看到,毕竟禁用后说不得还会启用。。。硬删当然就是数据灰灰,再也无法恢复的。如果软删用 PUT:/v1/users,那就和修改姓名冲突了。我是这样规划的,修改普通属性 PUT:/v1/users,禁用 PUT:/v1/users/status,删除 DELETE:PUT:/v1/users 。
  • jorneyr 12天前
    引用 44
    RESTful 在 URL 里是禁止使用动词的,但是很多时候有的 URL 中用动词来表达很自然,强制使用 RESTful 的风格的话会很难受
  • imhxc 12天前
    引用 45
    我一直有个问题,请教下。
    在实际业务中,各种需求都有,很难严格遵守 RESTful API,拿文章中的示例来说:

    GET /owners/1/pets/ 获取 id 为 1 的主人的所有宠物
    1. 如果区分角色怎么办,比如管理员获取 id 为 1 的主人的所有宠物,结果中包含所有状态的宠物;
    2. 其他人需要查看 id 为 1 的主人所有宠物,结果中只返回状态为「可公开」的宠物;

    这种怎么设计?
  • codingbody 12天前
    引用 46
    我有个问题问大家,为什么安全扫描的时候,不准我使用除了 GET 、POST 之外的请求,我认为请求的方式和安全没啥关系吧
  • DeWhite 12天前
    引用 47
    那个就一句话,吃屎啦。就是没有主语的,国内的很明显主语省略的句子还有很多。
  • xcstream 12天前
    引用 48
    这标题隐含意思就是不 rest 就不优秀(狗头)
  • 楼主 KalaSearch 12天前
    引用 49
    @imhxc 用 ACL 来控制,REST endpoint 没办法控制的
  • 楼主 KalaSearch 12天前
    引用 50
    @DeWhite 你说的是祈使句,祈使句当然可以没有主语(省略了第二人称主语)
  • forgaoqiang 12天前
    引用 51
    看了下 Discuz Q,真的几斤,完全的 RESTFUL 风格,patch delete 各种方法都用
  • grzhan 12天前
    引用 52
    @lovedebug 我个人觉得关于复杂查询不管是用 $filter 还是直接 POST 自定义方法(如 "_search" )都是可以的,具体看自己场景。
    事实上我们项目实际实践中,这种情况还是自定义 POST 方法用的比较多
  • GavinZZ 12天前
    引用 53
    ??
  • GavinZZ 12天前
    引用 54
    还有个叫车满满的。。。工资给开的还算可以 13K+ 14 薪,但是不推荐去,企业文化很奇葩
  • lovedebug 12天前
    引用 55
    @grzhan 嗯。$filter 需要写 parser 专门处理,否则会重复造轮子
  • grzhan 12天前
    引用 56
    @lovedebug 如果查询场景需求确实很复杂的业务的话,我们会考虑上 GraphQL 的
  • lovedebug 12天前
    引用 57
    @grzhan 主要是 GraphQL 对已有产品的 RESTful API 破坏性过大,ROI 也不够高,另外也考虑在微服务和 k8s 中 GraphQL 中心化并不是一个很完美的方案。其实主要的阻力是项目进度和同事。哈哈哈哈
  • dongxiaoxian 12天前
    引用 58
    好复杂
  • ChanKc 12天前
    引用 59
    @codingbody 没有,但是历史上发生过一些 HTTP server 对 PUT,DELETE 等请求实现不当,导致远程代码执行等漏洞。一些公司就会觉得索性禁了这些请求更好
  • 游客
    60
返回