前言
优雅的API接口会让前端后端在对接过程中达成一些默契,提供一些愉悦的开发体验,对API接口的质量提升也有很大的一些帮助,本文罗列一些我们团队在日常开发过程中达成的一些共识,可能部分只适合我们自己的团队,也可能部分不太符合国际标准,只是做一些分享,并不代表本文提及的设计和共识都是主流,也不代表本文未提及的部分都很拉垮。
我们的接口普遍采用了 POST JSON 方式,没有使用 RESTFUL 风格的接口规范:
我早前写过一篇文章《与其不标准的RESTFUL,不如POST一把梭》,大意是说,RESTFUL风格的接口的请求方法和访问资源一般很难界定,处理这些边界问题往往需要大量的思考,而且结果还不一定非常符合标准。
接口命名约定
-
清晰的API作用域
后端使用 Controller 层将相同作用域的接口放到一起,比如
/api/user/***即代表了 与用户相关 的部分接口,其他与用户不相关的部分接口不允许放到/user/下。 -
动宾语法的接口名称
使用
动词 + 形容词 + 资源名称的方式来定义一个接口,如get UserInfoupdate OrderStatusadd My Order,delete All Log做到看接口地址即清楚接口实现的功能
字段命名和数据类型约定
-
字明其意的字段名称
- 使用
List结尾表示传输的数据是数组,避免纠结名词的单复数形式是什么:
{ roleList: [] // 角色数组 }- 使用
Info结尾表示传输的数据是对象,前面的词表示对象的类型:
{ roleInfo: {} // 角色对象 }- 使用
Id结尾表示传输的数据可能是另一个对象的主键ID:
{ nickname: "Hamm", roleId: 1 // 该用户有一个角色,ID为1 }- 使用
Code结尾表示传输的数据可能是一个全局唯一的编码(可以输入,如不输入将自动生成):
{ id: 1, materialCode: "P20220123214" // 自动生成或手动输入,但一定全局唯一的编码 }- 使用
Time结尾表示传输的数据可能是一个服毫秒时间戳:
{ id: 1, createTime: 1692757563000 // 创建时间, 可自行按产品需求转换显示的时间 // 比如 😄一炷香之前 }- 使用
parentId,children表示树结构的父节点ID和子树列表:
{ id: 1091, parentId: 1, children:[ {...} ] }还有很多,罗列不完了。
- 使用
-
正确的数据格式返回
- 承诺是数组类型返回的数据,无数据时不允许返回
必须返回null[] - 承诺是布尔类型返回的数据,仅允许返回
truefalse,不允许返回等数字类型,不允许返回1,0"true""false""null"等其他任何值null - 承诺是数字类型的返回数据,仅允许返回
数字,不允许返回等其他任何数据null - 承诺返回的字段,即使没有任何值,对象中的属性必须存在且为
null, 不允许没有值的时候不返回字段 - 承诺是时间戳类型的返回数据,只允许返回
数字,不允许返回null - 承诺是字符串类型返回的数据,只允许返回
字符串,不允许返回null - 承诺是百(千)分比的返回数据,只允许返回对应的
小数且不需要,不需要带* 100%‰等
- 承诺是数组类型返回的数据,无数据时不允许返回
必要字段约定
所有的 数据库存储 数据 (Entity) 必须包含以下字段:
-
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 等技术栈实现一套基于面向对象的前后端统一开发全栈项目,欢迎关注: