修复(#4): 统一 API 响应格式 — ResponseErrorBean 补 data 字段

Closes part of HIF-4 (Stage 2 前端集成反馈 F9 - 全站响应格式)

F9 (P1): 全站响应统一 {code, msg, data} 三字段固定 shape
- ResponseSuccessBean.Data 去掉 omitempty → 空 payload 也返 "data":null
- ResponseErrorBean 加 Data interface{} 字段 → 错误响应也带 "data":null
- App 端强类型 decoder 依赖固定字段 shape,缺 data 键会解码失败

回归护栏 3 用例:
- TestResponseErrorBean_HasDataField: 错误响应必须含 "data":null
- TestResponseSuccessBean_DataAlwaysPresent: Success(nil) 也含 "data":null(防 omitempty 回退)
- TestResponseSuccessBean_WithPayload: 正常 payload 序列化正确

影响面:全站所有响应(不止 lottery),JSON 加字段/字段值变 null 对现有 client 无 breaking(宽松 decoder 全兼容)
CI 全绿;单 file 改动 revert 一步搞定
This commit is contained in:
2026-07-12 19:55:35 -07:00
committed by GitHub
parent cce147108c
commit eac0137069
2 changed files with 73 additions and 4 deletions
+19 -4
View File
@@ -1,9 +1,21 @@
// Package result 定义 HTTP 响应统一 envelope。
//
// HIF-4 F9:所有响应必须是三字段固定 shape {code, msg, data}data 为空时
// 也要显式 `null` —— 而不是靠 omitempty 丢字段。App 端强类型 decoderRetrofit /
// serde / typed structs)依赖这个 shape,缺字段会解码失败。
//
// 修改前:
// - Success 的 Data 带 omitemptynil payload 时 JSON 里没有 data 键
// - Error 结构体没有 Data 字段,错误响应永远缺 data 键
// 修改后:Success 和 Error 都有 Data 字段,且都 **不带 omitempty**。空场景下 JSON
// 一律出现 "data":null。加字段对旧 client 无 breaking impactJSON 忽略未知字段/
// 已知字段变 null 都能 decode 过)。
package result
type ResponseSuccessBean struct {
Code uint32 `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
Data interface{} `json:"data"` // F9: 不带 omitempty,空 payload 也返 data:null
}
type NullJson struct{}
@@ -11,11 +23,14 @@ func Success(data interface{}) *ResponseSuccessBean {
return &ResponseSuccessBean{200, "success", data}
}
// ResponseErrorBean 与 ResponseSuccessBean 结构对齐(都有 Data 字段),
// Data 在错误场景永远为 nil;序列化后 JSON 里显式为 "data":null。
type ResponseErrorBean struct {
Code uint32 `json:"code"`
Msg string `json:"msg"`
Code uint32 `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"` // F9: 错误响应也必须有 data 字段(值永远为 null)
}
func Error(errCode uint32, errMsg string) *ResponseErrorBean {
return &ResponseErrorBean{errCode, errMsg}
return &ResponseErrorBean{errCode, errMsg, nil}
}