RESTful API接口设计规范

2,819 阅读6分钟

Less can be more.

这篇文章主要是记录一下API设计的相关规范。

无规矩不方圆,根据规范统一代码风格,团队协作时,能更容易让彼此(的代码)相互理解,不至于别人一接手你的代码就两眼一抹黑,只想skfjgs!@#$%^&jk_(:з」∠)_

做人留一线,日后好相见。天道好轮回,下次还不知道是谁坑谁 o(╯□╰)o

协议

API与用户的通信协议,总是使用HTTPs协议,确保交互数据的传输安全。

Endpoint

路径又称“终点”(endpoint),表示API的具体URI。 在RESTful架构中,每个endpoint代表一种资源(resource),所以endpoint中不能有动词,只能有名词,而且所用的名词往往与数据库的表名对应。 一般来说,endpoint代表的是同种资源的“集合”(collection),所以API中的名词也应该使用复数。不过,具体使用还是要根据实际场景来灵活选择。

https://api.example.com/v1/products
https://api.example.com/v1/users
https://api.example.com/v1/employees

域名

  • 应该尽量将API部署在专用域名之下。 https://api.example.com
  • 如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。 https://example.org/api/

版本控制

  • 用于在同一个资源的两个API版本之间存在不兼容情况时区分版本
  • 不兼容的情况包括:入参、出参存在改名、删除情况;其他阻塞、不阻塞的修改。
  • 版本格式为字母v加上一个版本号 例如:https://api.example.com/v{n}/ n代表版本号,分为整形和浮点型。 整形的版本号:大功能版本发布形式,具有当前版本状态下的所有API接口。例如:v1,v2。 浮点型:为小版本号,只具备补充API的功能,其他API都默认调用对应大版本号的API。例如:v1.1,v2.2。

resource

  • 用于定位资源
  • resource可以包含多级路径
  • GET请求中,用于定位资源的标识变量,可以使用path_param放在路径中,如资源id。
  • 非GET请求不允许在resource后面加参数,必须把参数都放在请求体里。
  • 资源的命名方式要求用中划线“-”分隔的蛇形命名法,且所有字母小写。

请求头

  • Content-Type:application/json;charset=utf-8

HTTP动词使用

标准CRUD操作对应的HTTP动词如下。

GET

  • 获取资源
  • 必须具有幂等性
  • 不应该有body体
  • 当获取资源需要的过滤参数很少时,参数以query_param的形式跟在Endpoint后面
  • 当获取资源需要的过滤参数较多时,建议把参数封装成json格式,以query_param的形式跟在Endpoint后面。如:resources?query_param={"id":1,"name"="tony"}。注意发送请求前需要对query_param进行URL Encode处理。
  • 当获取资源需要的过滤参数较多时,也可以使用POST动词。

PUT

  • 若操作的URL为一个新资源,则新增该资源;若URL为一个已经存在的资源,则完整替换该资源。
  • 必须具有幂等性
  • 可以有body体
  • 无论新增成功还是替换成功,均必须返回成功
  • PUT操作传入的消息体必须包含被替换资源的完整信息。若传递信息不完整,则服务端需要提供对应字段的默认值。
  • 当被修改资源所需要修改的信息和替换全部信息差别不大时,应该优先使用PUT操作做整体替换,而不建议使用PATCH动词做部分更新,因为业界对PATCH动作的使用风格不统一,多数开发框架对PATCH动作的支持不完善,且PATCH动作做不到幂等性。

POST

  • 新增资源
  • 当资源标识由客户端创建时,必须具有幂等性,且应该优先使用PUT动作
  • 当资源标识由服务端创建时,无法做到幂等性,客户端谨慎使用重试功能
  • 可以有body体

DELETE

  • 删除资源
  • 必须具有幂等性
  • 不应该有body体
  • 无论删除成功,还是资源不存在,均必须返回成功

参数规范

参数的命名

  • 参数统一使用英文单词,下划线分隔的格式
  • 禁止使用非业界公认的缩写
  • 同一个概念使用统一的key命名,便于理解

空字段

  • 数值类型字段注意0和null在业务上的区别,在满足业务需求的前提下两者皆可用于返回
  • 字符串为空,或其他对象类型值为空,必须返回null,而不是空字符串"null"
  • null字段本身如果有子字段,其子字段不需要体现在返回数据里

枚举字段

  • 字段值为枚举项时,必须使用字符串,禁止使用数字。
  • 代表同一含义的枚举项字符串要保持一致。

时间参数

  • 时刻:对于某一个具体时刻,使用时间戳
  • 日期:对于一个日期,使用转换成UTC时间后的年月日格式,yyyy-MM-dd

HTTP Status Code

2xx

2xx状态码表示请求成功。

  • 200 OK:请求成功。
  • 201 Created:请求完成,资源创建成功。(POST)
  • 202 Accepted:请求已经被服务端接受,并且正在执行中,但尚未执行完成(Async process)

4xx

4xx状态码表示客户端错误。 如果无法确定使用哪个更精确的状态码,可以统一使用400。

  • 400 Bad Reqeust:服务器不理解客户端的请求,未做任何处理。
  • 401 Unauthorized:未认证,需要提供认证信息。
  • 403 Forbidden:访问被拒绝。
  • 404 Not Found:服务端找不到请求的资源。

5xx

5xx状态码表示服务端错误。一般来说,API不会向用户透露服务器的详细信息,所以只要500一个状态码就够了。

  • 500 Internal Server Error:客户端请求有效,服务区处理时发生了意外。

返回消息体

  • 一般返回消息体必须使用JSON格式,禁止XML格式封装
  • 文件下载等媒体传输使用特定格式
  • 异常场景使用错误码来区分不同的异常类型,使用message来简单说明错误原因
  • 在Java中,返回体中的data建议使用泛型,而非使用Object

API设计要求

查询资源列表的API要支持分页

  • 返回列表的API,如果无法一次返回所有数据,需要支持分页。一页返回的条数由客户端决定,但服务端要设置上限,建议上限一般不超过500条
  • 查询资源列表需要返回符合查询条件的资源总数,方便客户端做分页控制

过滤信息

如果记录梳理很多,服务器不可能将它们都返回给用户。API应该提供参数,过滤返回结果。

原子性

  • 原则上一个微服务提倡的是解耦,领域建模,如果一个API依赖其他几个API,可以考虑把编排业务逻辑移到客户端,保证自己的原子性。
  • 如果一次客户请求涉及到批量处理,则需要确保所有的资源全部处理完毕后返回成功。若中间发生失败,则回滚已经处理的资源,然后返回失败。若资源之间相互独立,无绑定或依赖关系,可以不回滚,但是要给出所有失败项的列表及原因。

参考资料