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,可以考虑把编排业务逻辑移到客户端,保证自己的原子性。
- 如果一次客户请求涉及到批量处理,则需要确保所有的资源全部处理完毕后返回成功。若中间发生失败,则回滚已经处理的资源,然后返回失败。若资源之间相互独立,无绑定或依赖关系,可以不回滚,但是要给出所有失败项的列表及原因。
参考资料
-
API接口规范[my.oschina.net/qqlet/blog/…]
-
HTTP - Status Codes[www.tutorialspoint.com/http/http_s…]