我们知道,很多软件和网站以 REST API 的形式对外提供服务,而同一个 API 端点在不同情形下(如执行成功或失败可能响应不同格式的响应体)。
例如,ElasticSearch 的某些 API 端点,执行成功(200)时,返回形如
{ "_id": "qwsDcf", "name": "fv-j"}
的响应体,执行失败(4xx 或 5xx)时,返回形如
{ "errCode": 4705, "errMsg": "晶矿不足"}
的响应体。
一段时间以前,在某个软件开发过程中,我设计了所负责的一个服务的 REST API。当然,大部分的端点,成功和失败有不同的响应体。这样设计很合理,以前用 Go 或 Python 开发后端程序的时候,这样做也是家常便饭。由于某种原因,这部分程序被设计成用 Java(Spring Boot)实现,我猛地发现,自己竟然不知道它如何用 Spring MVC 优美地实现它。当然,用 HttpServletResponse
硬写当然也可以,但实在太费事了。
问了几个同事,发现谁也没这么搞过,都是图省事,用同一个结构表示成功和失败:
{ "errCode": 0, // 错误码,0 表示正确 "errText": "", // 错误描述,如果错误码是 0,此处无意义 "result": { // 如果错误码是 0,则这里表示返回的结果 // }}
我非常倾向于用正宗的方式来做事。一次偶然的机会,发现它其实特简单,用 ResponseEntity<?>
就可以了,如下:
class Fuck { private String name; private String att; public Fuck(String name, String att) { this.name = name; this.att = att; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAtt() { return att; } public void setAtt(String att) { this.att = att; }}class Shit { private String errText; public Shit(String text) { this.errText = text; } public String getErrText() { return errText; } public void setErrText(String errText) { this.errText = errText; }}@RestController@RequestMapping(path = "/api/v1")public class MainController { @GetMapping(path = "/lr/{star}") public ResponseEntity getRedStar(@PathVariable String star) { if ("sgra".equals(star)) { return ResponseEntity.ok().body(new Fuck("sgra", "atk")); } else { return ResponseEntity.badRequest().body(new Shit("bad req")); } }}
用 HTTP 客户端测试一下
GET /api/v1/lr/sgra
返回 200,响应体为
{ "name": "sgra", "att":"atk"}
而
GET /api/v1/lr/sgra123
返回 400,响应体为
{ "errText": "bad req"}