接口设计没有标准答案,但有几条规则能显著降低调用方的理解成本。这次重构把服务里二十多个接口统一成了同一套约定。
URL 和资源
接口 URL 描述资源,动作交给 HTTP 方法:
GET /api/orders/{id}
POST /api/orders
PATCH /api/orders/{id}
DELETE /api/orders/{id}
动词尽量不进 URL。像 /api/getOrder 这类写法会让资源模型越来越乱。
返回结构
统一返回结构,方便前端做通用处理:
{
"code": 0,
"message": "ok",
"data": {}
}
业务失败也用 HTTP 200 加业务码返回,网络层错误才用 HTTP 状态码。这样网关、超时和业务失败可以分开处理。
错误码
错误码要有规律,不能随手编。可以用三段式:模块、场景、序号。
| 模块 | 前缀 | 示例 |
|---|---|---|
| 订单 | 100 | 100001 订单不存在 |
| 支付 | 200 | 200002 余额不足 |
| 用户 | 300 | 300003 未登录 |
public record ApiResponse<T>(int code, String message, T data) {
public static <T> ApiResponse<T> ok(T data) {
return new ApiResponse<>(0, "ok", data);
}
}
错误码文档必须和代码同源维护。这里直接由枚举生成文档,避免代码改完了文档还停留在旧版本。
几个容易忽略的点
- 分页参数统一叫
page和pageSize,从 1 开始; - 时间统一用 ISO 8601,避免时区歧义;
- 列表接口允许
sort白名单,不能把任意字段拼进 SQL; - 写接口返回创建后的完整对象,省掉一次回查。
这些约定单独看都很小,合在一起就能让整个服务的接口像同一套系统,而不是不同人随手写的补丁。