前言
优雅的API接口会让前端后端在对接过程中达成一些默契,提供一些愉悦的开发体验,对API接口的质量提升也有很大的一些帮助,本文罗列一些我们团队在日常开发过程中达成的一些共识,可能部分只适合我们自己的团队,也可能部分不太符合国际标准,只是做一些分享,并不代表本文提及的设计和共识都是主流,也不代表本文未提及的部分都很拉垮。
我们的接口普遍采用了 POST JSON 方式,没有使用 restful 风格的接口规范:
> 我早前写过一篇文章《与其不标准的rest,不如POST一把梭》,大意是说,rest风格的接口的请求方法和访问资源一般很难界定,处理这些边界问题往往需要大量的思考,而且结果还不一定非常符合标准。
接口命名约定
-
清晰的API作用域
后端使用 Controller 层将相同作用域的接口放到一起,比如
/api/user/***
即代表了 与用户相关 的部分接口,其他与用户不相关的部分接口不允许放到/user/
下。 -
动宾语法的接口名称
使用
动词+形容词+资源名称
的方式来定义一个接口,如get UserInfo
update OrderStatus
add My Order
,delete All Log
做到看接口地址即清楚接口实现的功能
字段命名和数据类型约定
-
字明其意的字段名称
- 使用
List
结尾表示传输的数据是数组,避免纠结名词的单复数形式是什么:
{ roleList: [] // 角色数组 }
- 使用
Info
结尾表示传输的数据是对象,前面的词表示对象的类型:
{ roleInfo: {} // 角色对象 }
- 使用
Id
结尾表示传输的数据可能是另一个对象的主键ID:
{ nickname: "Hamm", roleId: 1 // 该用户有一个角色,ID为1 }
- 使用
Code
结尾表示传输的数据可能是一个全局唯一的编码(可以输入,如不输入将自动生成):
{ id: 1, materialCode: "P20220123214" // 自动生成或手动输入,但一定全局唯一的编码 }
- 使用
Time
结尾表示传输的数据可能是一个服务器所在时区的毫秒时间戳(依赖服务器时区,适合L10n
项目,稍加改造即可支持I18n
):
{ id: 1, createTime: 1692757563000 // 创建时间, 可自行按产品需求转换显示的时间 // 比如 😄一炷香之前 }
- 使用
parentId
,children
表示树结构的父节点ID和子树列表:
{ id: 1091, parentId: 1, children:[ {...} ] }
还有很多,罗列不完了。
- 使用
-
正确的数据格式返回
- 承诺是数组类型返回的数据,无数据时不允许返回
必须返回null
[]
- 承诺是布尔类型返回的数据,仅允许返回
true
false
null
,不允许返回1,0
等数字类型,不允许返回"true"
"false"
,"null"
等其他任何值 - 承诺是数字类型的返回数据,仅允许返回
数字
,null
不允许返回其他任何数据 - 承诺返回的字段,即使没有任何值,对象中的属性必须存在且为
null
, 不允许没有值的时候不返回字段 - 承诺是时间戳类型的返回数据,只允许返回
数字
,不允许返回null
- 承诺是字符串类型返回的数据,只允许返回
字符串
,不允许返回null
- 承诺是百分比的返回数据,只允许返回对应的
小数
且不需要X100
- 承诺是数组类型返回的数据,无数据时不允许返回
必要字段约定
所有的 数据库存储
数据必须包含一下字段:
-
ID
主键ID表示主键ID,数字类型,所有CURD接口的索引字段(某些场景下的
code
也可以作为索引字段) -
createTime
首次创建时间首次创建的时间,毫秒时间戳,可作为排序使用,一旦创建不允许修改
-
updateTime
最后修改时间最后修改的时间,毫秒时间戳,可作为排序使用,不允许手动修改,系统自动更新
明确的异常提示
任何服务端出现的异常,包括但不限于 服务端BUG 前端传参验证问题 服务侧网络问题 第三方依赖问题 ,所有环境都应抛出文案优化后的具体错误信息,不允许直接全局抛出 这种不明确错误内容的错误信息,否则无法高效的排除错误。 生产环境 未及时捕获的异常应返回文案优化后的模糊错误提醒, 如 请求错误
“操作出现异常,请稍后再试或联系客服”
,且应及时分析对应的错误信息,捕获并处理异常后优化文案返回具体的错误信息。
所有的异常返回不允许返回一些敏感信息,如数据库连接地址、账号密码等。
明确返回的标准JSON结构
整个http返回状态码固定为200,其中返回的body数据为 JSON
且标准返回如下:
{
"code": 200,
"message": "获取成功",
"data": ... // data为可选
}
其中, code为状态码,为整数数字类型,尊重以下规则:
200
为操作成功,表示客户端后续无必要操作201
为操作成功,但后续还有必要操作401
为需要跳转到登录页面503
为繁忙表示,表示本次请求没有成功,但前端可能需要重新发起请求404
查询的数据不存在,前端可能需要打开新增页面405
请求没有使用POST请求415
请求没有使用JSON交互501
不存在的请求接口,需要确认请求API地址是否正确50x
其他服务端提示的错误信息- 其他状态码,参考具体的业务逻辑
任何阶段的接口高可用
如后端使用编译型语言开发,经常会碰到修复完一个BUG之后提交到开发服务器部署,导致发布重启阶段接口不可用,我们要求:
> 在任何阶段(开发、测试、生产)都必须提供备用服务
进行负载,尽可能保证任何情况下服务端 http 状态码的返回均是 200
标准的接口文档和版本管理
接口文档需要满足以下一些规则:
- 标准的文档格式,必须提供
url
参数
响应结构
- 提供枚举类型,必须提供枚举可选项的
枚举值
枚举显示值
- 提供必填字段、必填场景以及校验规则
- 所有文档的变更必须提供变更记录和说明
That's all
今天的分享就到这里,下一篇我们继续。
欢迎在评论区分享你们的一些规范或者设计方式,大家互相学习和讨论。
我们最近在使用 vue3
TypeScript
ElementPlus
Java
SpringBoot
JPA
等技术栈实现一套基于面向对象的前后端统一开发全栈项目,欢迎关注: