规范原则
- 接口返回数据即展示:前端仅做渲染逻辑的处理;
- 渲染逻辑禁止夸多个接口调用;
- 前端关注交互、渲染逻辑,尽量避免业务逻辑处理的出现;
- 请求数据传输格式:RESTful API 风格
- 响应数据传输格式:JSON 数据尽量简单轻量,避免多级JSON的出现;
请求数据格式(RESTful)
理解 RESTful
版本号
在 RESTful API 中,API 接口应该尽量兼容之前的版本。但是,在实际业务开发场景中,可能随着业务需求的不断迭代,现有的 API 接口无法支持旧版本的适配,此时如果强制升级服务端的 API 接口将导致客户端旧有功能出现故障。实际上,Web 端是部署在服务器,因此它可以很容易为了适配服务端的新的 API 接口进行版本升级,然而像 Android 端、IOS 端、PC 端等其他客户端是运行在用户的机器上,因此当前产品很难做到适配新的服务端的 API 接口,从而出现功能故障,这种情况下,用户必须升级产品到最新的版本才能正常使用。
为了解决这个版本不兼容问题,在设计 RESTful API 的一种实用的做法是使用版本号。一般情况下,我们会在 url 中保留版本号,并同时兼容多个版本。【GET】 /v1/users/{user_id} // 版本 v1 的查询用户列表的 API 接口【GET】 /v2/users/{user_id} // 版本 v2 的查询用户列表的 API 接口
现在,我们可以不改变版本 v1 的查询用户列表的 API 接口的情况下,新增版本 v2 的查询用户列表的 API 接口以满足新的业务需求,此时,客户端的产品的新功能将请求新的服务端的 API 接口地址。虽然服务端会同时兼容多个版本,但是同时维护太多版本对于服务端而言是个不小的负担,因为服务端要维护多套代码。这种情况下,常见的做法不是维护所有的兼容版本,而是只维护最新的几个兼容版本,例如维护最新的三个兼容版本。在一段时间后,当绝大多数用户升级到较新的版本后,废弃一些使用量较少的服务端的老版本API 接口版本,并要求使用产品的非常旧的版本的用户强制升级。
注意的是,“不改变版本 v1 的查询用户列表的 API 接口”主要指的是对于客户端的调用者而言它看起来是没有改变。而实际上,如果业务变化太大,服务端的开发人员需要对旧版本的 API 接口使用适配器模式将请求适配到新的API 接口上。
资源路径
RESTful API 的设计以资源为核心,每一个 URI 代表一种资源。因此,URI 不能包含动词,只能是名词。注意的是,形容词也是可以使用的,但是尽量少用。一般来说,不论资源是单个还是多个,API 的名词要以复数进行命名。此外,命名名词的时候,要使用小写、数字及下划线来区分多个单词。这样的设计是为了与 json 对象及属性的命名方案保持一致。例如,一个查询系统标签的接口可以进行如下设计。
【GET】 /v1/tags/{tag_id}
同时,资源的路径应该从根到子依次如下
/{resources}/{resource_id}/{sub_resources}/{sub_resource_id}/{sub_resource_property}
我们来看一个“添加用户的角色”的设计,其中“用户”是主资源,“角色”是子资源。
【POST】 /v1/users/{user_id}/roles/{role_id} // 添加用户的角色
有的时候,当一个资源变化难以使用标准的 RESTful API 来命名,可以考虑使用一些特殊的 actions 命名。
/{resources}/{resource_id}/actions/{action}
举个例子,“密码修改”这个接口的命名很难完全使用名词来构建路径,此时可以引入 action 命名。
【PUT】 /v1/users/{user_id}/password/actions/modify // 密码修改
请求基本格式
响应实体格式(JSON)
响应基本格式
{
"code": "S00200",
"message": "操作成功",
"sign": 1,
"body": {}
}
| 响应字段 | 字段描述 | 备注 |
|---|---|---|
| code | 响应代码 | |
| message | 响应描述 | |
| sign | 响应标记 | 1-操作成功,0-操作无结果 |
| body | 承载数据 |
响应实体格式
{
"code": "S00200",
"message": "操作成功",
"sign": 1,
"body": {
"sid": "1000000000000000010",
"remarks": "备注",
"createTime": "2021-03-12 18:48:08",
"enable": 1
}
}
| 响应字段 | 字段描述 | 备注 |
|---|---|---|
| code | 响应代码 | |
| message | 响应描述 | |
| sign | 响应标记 | 1-操作成功,0-无承载数据 |
| body | 承载数据 | 实体数据内容 |
响应列表格式
{
"code": "S00200",
"message": "操作成功",
"sign": 1,
"body": [
{
"typeCode": "SYS00003",
"value": "0",
"desc": "女",
"sort": 3,
"dictDefault": 0
},
{
"typeCode": "SYS00003",
"value": "1",
"desc": "男",
"sort": 3,
"dictDefault": 0
}
]
}
| 响应字段 | 字段描述 | 备注 |
|---|---|---|
| code | 响应代码 | |
| message | 响应描述 | |
| sign | 操作标记 | 1-操作成功,0-无承载数据 |
| body | 承载数据 | 列表数据内容 |
响应分页格式
{
"code": "S00200",
"message": "操作成功",
"sign": true,
"body": {
"rows": [
{
"sid": 1000000000000000001,
"name": '张三',
},
{
"sid": 1000000000000000002,
"name": '李四'
}
],
"total": 10,
"pages": 1,
"page": 1,
"limit": 10
}
}
| 响应字段 | 字段描述 | 备注 |
|---|---|---|
| code | 响应代码 | |
| message | 响应描述 | |
| sign | 操作标记 | 1-操作成功,0-无承载数据 |
| body | 承载数据 | |
| rows | 列表数据 | |
| total | 数据总数 | |
| pages | 总页数 | |
| page | 当前页码 | |
| limit | 偏移量(每页条数) |
特殊内容规范
下拉框、复选框、单选框
由后端接口逻辑判定是否选中,通过标识是否选中,示例如下:
{ "code": "S00200", "message": "操作成功", "sign": 1, "body": [ { "value": "0", "desc": "女", "sort": 3, "defaultValue": 0 }, { "value": "1", "desc": "男", "sort": 3, "defaultValue": 0 }, { "value": "2", "desc": "未知", "sort": 3, "defaultValue": 1 } ] }Boolean类型
JSON数据传输中一律使用1、0来表示,1=true/是,0=false/否
后端在通用模块中配置,基础JSON转换
日期格式
- 关于日期格式,JSON传输中一律使用字符串,正常情况下默认为此格式:
- 时间:HH:mm:ss
- 年月日:yyyy-MM-dd
- 年月日时分秒:yyyy-MM-dd HH:mm:ss
{
"code": "S00200",
"message": "操作成功",
"sign": 1,
"body": {
"localDateTime": "2021-11-18 14:45:00",
"localDate": "2021-11-18",
"localTime": "14:45:00"
}
}
