后端 API 规范
此规范为 RESTful Api 定义了一个与语言无关的标准接口规范。使开发者或程序都能更快的理解服务功能。
后端 API 规范。持续补充...
目录
- 路径
- HTTP Status Codes
- 字段类型
- 键名规范
- 请求返回值
路径
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。路径二级域名api.xxx.com开头。路径命名使用驼峰写法。
GET https://api.example.com/animal 列出所有动物
GET https://api.example.com/animal/carnivorousAnimal 列出所有动物里面的食肉动物
POST https://api.example.com/animal 新建一个动物
GET https://api.example.com/animal/id 获取某个指定动物的信息
PUT https://api.example.com/animal/id 更新某个指定动物的信息
DELETE https://api.example.com/animal/id 删除某个指定动物的信息
前端系统域名前缀默认wechat
GET https://api.example.com/wechat/animal 列出所有动物
后台系统域名前缀默认admin
GET https://api.example.com/admin/animal 列出所有动物
HTTP Status Codes
100-(消息)—— 服务器接受到请求
200-(成功)——服务器按照预期完成请求处理
300-(重定向)——客户端需要执行进一步的操作来完成请求
400-(客户端出错)——客户端请求无效
500-(服务器出错)——服务器出错,请求无法正常执行
正常返回使用200
状态码。如遇到客户端返错误(优惠券已领取,命名重复等)使用400
状态码
已存在code语义介绍IANA Status Code Registry.
字段类型
类型 | 对应类型 | 例子 | 文档 |
---|---|---|---|
boolean | boolean | ||
integer | int32 | ||
integer | int64 | ||
number | float | ||
number | double | ||
string | |||
string | byte | base64 encoded characters | |
string | binary | any sequence of octets | |
integer | date | 1598915491000 |
字段空值处理
项目使用spring boot jackson
序列化时如果配置了如下配置
spring:
jackson:
default-property-inclusion: NON_NULL
空值序列化时将会被忽略。这有利于减少接口返回的数据体大小。默认开启。 因而对于前端来说,取值要对 null 做处理。
日期处理
项目使用spring boot jackson
序列化时如果配置了如下配置
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
日期默认处理成yyyy-MM-dd HH:mm:ss
格式。因此无需再接口返回的模型上增加日期处理。除非日期只包含年月日,那就需要额外处理,否则不用。
其他注意事项
- 禁止使用 0 1 表示
boolean
。 - 对数值计算有特殊要求的使用
string
返回。
键名规范
语义化键名,并且遵循驼峰命名法
请求返回值
- 非导出接口统一使用
JsonResult
对象进行包裹
{
"code": 0,
"data": {},
"msg": "string"
}
code 状态码如下:
OK(0, "OK"),
BAD_REQUEST(40000, "参数错误"),
UNAUTHORIZED(40001, "未授权或登录已过期"),
NO_POWER(40002, "权限不足"),
PASSWORD_ERROR(40003, "账号密码错误"),
INVALID_TOKEN(40004, "无效的令牌"),
DISABLE_USER(40005, "用户被禁用"),
SERVER_ERROR(50000, "服务器开了点小差,请稍后再试!"),
UN_REGISTER(50001, "未注册"),
ILLEGAL(50002, "非正常请求"),
SERVICE_RESTART(50003, "服务重启中,请稍后"),
NO_STANDARD(50004, "接口不符合开发规范"),
NULL_ERROR(50005, "NULL异常"),
INELIGIBLE_ERROR(50006, "不符合条件"),
SESSION_KEY_ERROR(50007, "sessionKey不存在或已过期");
code为0
表示业务成功。仅针对httpcode
为200
的情况。
- 导出接口统一使用
void
对象进行包裹
接口例子
@Api(tags = "Banner")
@RestController
@RequestMapping("/mall/banner")
@RequiredArgsConstructor
public class BannerController {
private final BannerService bannerService;
@ApiOperation("列表")
@GetMapping
public JsonResult<PagedResult<BannerOutputDto>> list(BannerQuery dto) {
return JsonResult.ok(this.bannerService.list(dto));
}
@ApiOperation("详情")
@GetMapping("{id}")
public JsonResult<BannerOutputDto> get(@PathVariable("id") Long id) {
return JsonResult.ok(this.bannerService.get(id));
}
@ApiOperation("新增")
@PostMapping
public JsonResult<Long> insert(@RequestBody @Validated BannerCreateInputDto dto) {
return JsonResult.ok(this.bannerService.insert(dto));
}
@ApiOperation("编辑")
@PutMapping("{id}")
public JsonResult<Void> update(@PathVariable("id") Long id, @RequestBody @Validated BannerModifyInputDto dto) {
dto.setId(id);
this.bannerService.update(dto);
return JsonResult.ok();
}
@ApiOperation("修改状态")
@PutMapping("{id}/status")
public JsonResult<Void> updateStatus(@PathVariable("id") Long id, @RequestBody @Validated BannerModifyStatusInputDto dto) {
dto.setId(id);
this.bannerService.updateStatus(dto);
return JsonResult.ok();
}
@ApiOperation("删除")
@DeleteMapping("/delete/{id}")
public JsonResult<Void> delete(@PathVariable("id") Long id) {
this.bannerService.delete(id);
return JsonResult.ok();
}
@ApiOperation(value = "导出列表")
@GetMapping("/export")
public void export(HttpServletResponse response, BannerQuery query) {
List<BannerPoiDto> list = BeanCopierUtil.copyLists(this.bannerService.list(query), BannerPoiDto.class);
EasyPoiUtil.exportExcel(list, "banner列表", BannerPoiDto.class, response);
}
}
前后端沟通的桥梁
后端项目会进行swagger
集成,而后导入到apifox,前后端接口沟通的桥梁便在于此。为了更好的沟通,注释的编写尤为重要。以下是一些示例:
- body 数据结构
@Data
public class SigninTaskInputDto {
@ApiModelProperty(value = "签到方式", notes = "com.wmeimob.mall.core.mall.user.signin.value.SigninType")
@NotNull(message = "签到不能为空")
@RangeExtend(value = SigninType.class, message = "签到方式有误")
private Integer type;
@ApiModelProperty("说明")
private String description;
}
@PostMapping
@ApiOperation("保存签到任务信息")
public JsonResult<Void> save(@RequestBody @Validated SigninTaskInputDto dto) {
this.signinService.saveSigninTaskInfo(dto);
return JsonResult.ok();
}
示例save
接口定义了一个SigninTaskInputDto
对象,通过编写@ApiModelProperty
注解来表达属性的注释。其中,对于枚举类型有个扩展,可以定义notes
属性为枚举类型的全类名,swagger
扩展会去读取这个属性并解析成全新的描述文本。那这其中,这个枚举有什么格式要求吗?它支持
- 原生枚举
- 实现接口
EnumValue
的枚举类
最终效果如图
- 非 body 数据结构
@PutMapping
@ApiOperation(value = "签到")
public JsonResult<SigninSimpleOutputDto> signin(
@RequestParam(name = "signinType", defaultValue = "2")
@ApiParam(name = "type", value = "签到类型", type = "com.wmeimob.mall.core.mall.user.signin.value.SigninType") Integer signinType) {
return JsonResult.ok(this.signinService.signin(signinType));
}
示例signin
接口定义了一个参数,通过编写@ApiParam
注解来表达属性的注释。其中,对于枚举类型有个扩展,可以定义type
属性为枚举类型的全类名,swagger
扩展会去读取这个属性并解析成全新的描述文本。那这其中,这个枚举有什么格式要求吗?它支持
- 原生枚举
- 实现接口
EnumValue
的枚举类
最终效果如图