REST风格的后端接口规范 写在前面 请求方式 请求地址 请

写在前面

众所周知规范的HTTP接口由请求方式、请求参数、请求地址、响应数据、统一异常拦截构成。所以本文从这五个方面入手,规范接口,减少前后端联调时间!本文基于REST的风格规范后端接口,对REST的说明可以参考这篇文章:www.ruanyifeng.com/blog/2011/0…

请求方式

使用HTTP的请求方式代表操作资源的动作,定义接口时要根据业务选择适合的请求方式,常见的HTTP请求有5种:

1
2
3
4
5
markdown复制代码1. GET: 从服务器查询出一个或多个数据
2. PUT: 更新服务器完整资源
3. PATCH: 更新服务器部分资源
4. POST: 新增资源
5. DELETE: 删除资源

请求地址

请求地址就是URL,我们已经用HTTP请求代表操作资源的动作了,所以我们在URL中就不应该出现动作。

假设场景设计一个接口操作公司的部门和员工,下面给出规范的URL的例子:

查询示例

1
2
3
4
5
6
7
8
bash复制代码1. 查询所有部门
GET /department
2. 根据部门编号查询部门信息
GET /department/{id}
3. 根据部门编号,员工编号查询员工
GET /account/{id}/department/{id}
4. 分页查询部门
GET /department?currentPage=1&pageSize=10

新增示例

1
2
3
4
bash复制代码1. 新增部门
POST /department
2. 新增员工
POST /account

更新示例

1
2
3
4
bash复制代码1. 更新部门除主键的所有信息
PUT /department
2. 更新部门的名称
PUT /department

删除示例

1
2
3
4
5
bash复制代码1. 删除部门
DELETE /department/{id}

1. 删除某部门中名叫狗剩的员工
DELETE /account/{name}/department/{id}

请求参数

新增和更新

前端在调用新增和更新接口时传递的是一个对象,所以当请求参数个数等于1时,可以直接接收此参数,当参数大于1时需要新建一个DTO对象来接收

方便接口调用方调用,我们要把对象和属性写上详细的swagger注释(
该类的作用、该值的作用、格式规则、示例)。

具体示例参考下面代码,节约篇幅省去了getter和setter:

1
2
3
4
5
6
7
8
9
kotlin复制代码@ApiModel("部门对象")
public class DepartmentDto {
@ApiModelProperty(value ="部门id、不得超过6位",example = "1")
private Integer id;
@ApiModelProperty(value ="部门名称、不得超过10位",example = "市场部")
private String name;


}

查询和删除

查询和删除不能新建一个对象来接受,所以只能在接口处定义swagger注释(该值的作用、格式规则、示例),并且描述该接口的作用、错误码的返回、成功的返回;

1
2
3
4
5
6
7
8
9
10
less复制代码 @ApiOperation(value = "根据部门id查询部门信息", notes = "根据部门id查询部门信息")
@GetMapping("/{id}")
@ApiResponses(value = {@ApiResponse(code = 200, message = "查询成功"),
@ApiResponse(code = 500, message = "systemError<br>"
+ "lengthError<br>")})
@ApiImplicitParam(name = "id",value = "部门id、不得超过6位",example = "1")
public Result<DepartmentDto> getList(@PathVariable("id") String id){
//假装查询哈
return Result.success("查询成功",new DepartmentDto());
}

响应数据

前后端分离时,我们需要定义统一的返回数据格式,并且对异常也要全局拦截。

统一返回数据对象

统一返回对象应包括以下字段,code:Http状态码message:错误码data:返回数据

  • 这三个字段应加上swagger注释;
  • 构造方法私有化、新建静态的构建方法以便快速得到;
  • 为打印日志方便可以重写toString方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
kotlin复制代码@ApiModel("统一返回对象")
public class Result<T> {

@ApiModelProperty("HTTP 请求状态码")
private String code;
@ApiModelProperty("返回的错误码")
private String message;
@ApiModelProperty("返回数据")
private T data;
private static final String success = HttpStatus.OK.value()+"";
private static final String fail = HttpStatus.INTERNAL_SERVER_ERROR.value()+"";

private Result(String code, String message, T t) {
this.code = code;
this.message = message;
this.data = t;
}

public static Result success(String message,Object data){
return new Result(success,message,data);
}
}

全局异常拦截

异常码

新建一个异常码的枚举,方便管理存储和返回异常;代码中含有no和code的字段,code用于返回前端,no的可以由自己的业务规则生成,将这个no打印在日志中,方便日后排查问题;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
typescript复制代码public enum ExceptionEnum {

SYSTEM_ERROR("010-1000000","systemError");


private final String no;
private final String code;



ExceptionEnum(String no, String code) {
this.no = no;
this.code = code;
}

public String getNo() {
return no;
}


public String getCode() {
return code;
}

@Override
public String toString() {
return this.code;
}

}

全局异常类

新建全局异常码枚举,使用异常码管理异常;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
scala复制代码public class BusinessException extends RuntimeException {

private static final long serialVersionUID = 1L;
private ExceptionEnum exceptionEnum;
private Object data ;

/**
* Instantiates a new Iam base exception.
*/
public BusinessException() {

}



public BusinessException(ExceptionEnum exceptionEnum) {
super(exceptionEnum.getCode());
this.exceptionEnum = exceptionEnum;
}
}

异常拦截

全局异常拦截,如果是业务异常则返回业务返回的错误码;如果是系统内部的错误比如空指针异常等等则抛出系统异常(这样处理是为了统一返回,方便前端处理,空指针异常只是示例,如果真的抛出空指针异常就要好好思考下为什么没判空!!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kotlin复制代码@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)
public Result exception(Exception e) {
return Result.fail(ExceptionEnum.SYSTEM_ERROR.getCode());
}

@ExceptionHandler(BusinessException.class)
public Result exception(BusinessException e) {
return Result.fail(e.getCode());
}

}

接口规范示例

GET 和DELETE 接口示例

添加@ApiOperation 描述该方法

添加@ApiResponses 描述成功和失败的message 、Http请求的状态码

添加@ApiImplicitParam 描述传入参数、格式限制、默认值

1
2
3
4
5
6
7
8
9
10
less复制代码 @ApiOperation(value = "根据部门id查询部门信息", notes = "根据部门id查询部门信息")
@GetMapping("/{id}")
@ApiResponses(value = {@ApiResponse(code = 200, message = "查询成功"),
@ApiResponse(code = 500, message = "systemError<br>"
+ "lengthError<br>")})
@ApiImplicitParam(name = "id",value = "部门id、不得超过6位",example = "1")
public Result<DepartmentDto> getList(@PathVariable("id") String id){
//假装查询哈
return Result.success("查询成功",new DepartmentDto());
}

POST、PUT、PATCH接口示例

1
2
3
4
5
6
7
8
9
less复制代码@ApiOperation(value = "新增部门信息", notes = "新增部门信息")
@PostMapping("/")
@ApiResponses(value = {@ApiResponse(code = 200, message = "新增成功"),
@ApiResponse(code = 500, message = "systemError<br>"
+ "lengthError<br>")})
public Result add(@RequestBody DepartmentDto dto){
//假装新增哈
return Result.success("新增成功",null);
}

API文档

按照上述的代码所写,得到的swagger文档如图:

代码

示例代码已经上传至www.fizzed.top/archives/ji…

写在最后

欢迎大家关注我的公众号【有一只基的程序猿】,一起交流Java、大数据,文章对应的脑图也会放在公众号里。 点关注,不迷路!!!

博客地址: www.fizzed.top

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%