package handlers import ( "fmt" "net/http" "github.com/gin-gonic/gin" ) // APIOK 返回统一成功响应。 // redirect 非空时附带相对跳转地址(原 302 目标,可含 ?saved=1 等 query); // data 额外字段会合并进响应。 func APIOK(c *gin.Context, redirect string, data gin.H) { resp := gin.H{"ok": true} if redirect != "" { resp["redirect"] = redirect } for k, v := range data { resp[k] = v } c.JSON(http.StatusOK, resp) } // APIError 返回统一错误响应:{ok:false, code, error}。 // trKey 是 i18n 键,直接作为 code 返回;error 为该键按请求语言的翻译文案。 // trKey 为空时回退到通用键 "api_error"。 func APIError(c *gin.Context, status int, trKey string) { tr := getTr(c) code := trKey if code == "" { code = "api_error" } msg := tr[code] if msg == "" { msg = tr["api_error"] } c.JSON(status, gin.H{ "ok": false, "code": code, "error": msg, }) } // APIErrorf 同 APIError,但 i18n 文案可按 fmt.Sprintf 格式化 // (针对含 %d/%s 占位符的键,如 comments_too_long)。 func APIErrorf(c *gin.Context, status int, trKey string, args ...interface{}) { tr := getTr(c) msg := tr[trKey] if msg == "" { msg = tr["api_error"] } else if len(args) > 0 { msg = fmt.Sprintf(msg, args...) } c.JSON(status, gin.H{ "ok": false, "code": trKey, "error": msg, }) } // bindJSON 将 JSON 请求体绑定到 v。 // 绑定失败时返回 400 + api_invalid_request,并返回 false。 // 使用前必须保证请求是 JSON(Content-Type: application/json)。 func bindJSON(c *gin.Context, v interface{}) bool { if err := c.ShouldBindJSON(v); err != nil { APIError(c, http.StatusBadRequest, "api_invalid_request") return false } return true }