采取 RESTful 风格的 api 是否应该对结果包一层?
又是基于 HTTP 的 API 设计问题
我个人的想法是:
-
RESTful 和 RPC 风格各有优劣,具体场景具体分析,但是整体一致最重要,不一致的 API 始终是最糟糕的。
-
如果要添加错误码,错误码最好放在 HTTP 头里面,这样可以在不读取 payload 的情况下判断是否存在错误
例如:
X-Error-Code: 10001
或者X-Error-Code: OUT_OF_CREDIT
注意 HTTP 头的值只能使用 ASCII 码的子集
-
如果你使用 RESTful 风格的 API design,那么在成功时应该尽量 避免额外包裹响应数据,也就是使用:
{ "id": 1, "name": "John" }
避免:
{ "data": { "id": 1, "name": "John Due" } }
在失败时应该有固定的响应结构,例如
{ // toast 消息 "message": "余额不足", }
在业务需要的情况下,失败时可以有更多的额外数据,比如
{ "message": "表单错误", // 额外的错误内容,提供给前端在代码内部进行判断 "extra": [ { "type": "validation_error", "field_name": "username", "message": "用户名不能包含 -" }, { "type": "validation_error", "field_name": "password", "message": "密码不能少于 6 位" } ] }
(这部分参考了 gRPC 的错误接口设计)
-
如果你只想要 RPC 的语义,那么可以考虑按 RPC 的方式来设计 API,或者直接上 gRPC
关于错误码,我个人的思考是:
- 避免定义太多错误码,如 Google API design guide 所说, 定义太多的错误码非常不友好,实际上开发者也不会检查那么多错误。
- 如果是某个场景出错时需要在程序上判断错误类型,可以把它放到响应的
extra
字段中,由前端进行判断。 - 如果很多场景都有共同的需要在代码中判断的错误类型时,可以为它添加一个错误码
总体上来说,我个人的设计原则是:如果一个接口前端不需要在代码中判断错误类型并进行处理,就不需要加入错误码,也不需要在 extra
字段加入额外的错误描述信息。
以及,IETF 有一个关于 HTTP API 错误的 RFC,也可以拿来参考。
(居然写了这么多 = =)