package response import ( "net/http" "github.com/gin-gonic/gin" apperrors "with_you/internal/errors" ) // Response 统一响应结构 type Response struct { Code int `json:"code"` Message string `json:"message"` Data any `json:"data,omitempty"` } // Success 成功响应 func Success(c *gin.Context, data any) { c.JSON(http.StatusOK, Response{ Code: 0, Message: "success", Data: data, }) } // SuccessWithMessage 成功响应带消息 func SuccessWithMessage(c *gin.Context, message string, data any) { c.JSON(http.StatusOK, Response{ Code: 0, Message: message, Data: data, }) } // Error 错误响应 func Error(c *gin.Context, code int, message string) { c.JSON(http.StatusBadRequest, Response{ Code: code, Message: message, }) } // ErrorWithStatusCode 带状态码的错误响应 func ErrorWithStatusCode(c *gin.Context, statusCode int, code int, message string) { c.JSON(statusCode, Response{ Code: code, Message: message, }) } // BadRequest 参数错误 func BadRequest(c *gin.Context, message string) { ErrorWithStatusCode(c, http.StatusBadRequest, 400, message) } // Unauthorized 未授权 func Unauthorized(c *gin.Context, message string) { if message == "" { message = "unauthorized" } ErrorWithStatusCode(c, http.StatusUnauthorized, 401, message) } // Forbidden 禁止访问 func Forbidden(c *gin.Context, message string) { if message == "" { message = "forbidden" } ErrorWithStatusCode(c, http.StatusForbidden, 403, message) } // NotFound 资源不存在 func NotFound(c *gin.Context, message string) { if message == "" { message = "resource not found" } ErrorWithStatusCode(c, http.StatusNotFound, 404, message) } // InternalServerError 服务器内部错误 func InternalServerError(c *gin.Context, message string) { if message == "" { message = "internal server error" } ErrorWithStatusCode(c, http.StatusInternalServerError, 500, message) } // PaginatedResponse 分页响应 type PaginatedResponse struct { List any `json:"list"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` TotalPages int `json:"total_pages"` } // Paginated 分页成功响应 func Paginated(c *gin.Context, list any, total int64, page, pageSize int) { totalPages := int(total) / pageSize if int(total)%pageSize > 0 { totalPages++ } Success(c, PaginatedResponse{ List: list, Total: total, Page: page, PageSize: pageSize, TotalPages: totalPages, }) } // HandleError 统一处理错误(带默认消息) // 如果 err 是 *apperrors.AppError,返回对应的业务错误码和消息 // 如果 err 是其他错误,返回 InternalServerError 并使用 defaultMessage func HandleError(c *gin.Context, err error, defaultMessage string) { if err == nil { return } if se, ok := apperrors.As(err); ok { statusCode := statusCodeFromAppErrorCode(se.Code) ErrorWithStringCode(c, statusCode, se.Code, se.Message) return } InternalServerError(c, defaultMessage) } // statusCodeFromAppErrorCode 根据AppError的错误码字符串获取 HTTP 状态码 func statusCodeFromAppErrorCode(code string) int { switch code { case "NOT_FOUND", "USER_NOT_FOUND", "POST_NOT_FOUND", "GROUP_NOT_FOUND", "GROUP_REQUEST_NOT_FOUND", "SCHEDULE_COURSE_NOT_FOUND", "VERIFICATION_NOT_FOUND", "CALL_NOT_FOUND": return http.StatusNotFound case "UNAUTHORIZED", "INVALID_TOKEN", "TOKEN_EXPIRED", "SESSION_REVOKED": return http.StatusUnauthorized case "INVALID_CREDENTIALS": return http.StatusBadRequest case "FORBIDDEN", "NOT_GROUP_MEMBER", "NOT_GROUP_ADMIN", "NOT_GROUP_OWNER", "USER_BANNED", "USER_BLOCKED", "MUTED", "MUTE_ALL_ENABLED", "SCHEDULE_FORBIDDEN", "UNAUTHORIZED_NOTIFICATION", "ACCOUNT_INACTIVE", "WRONG_TOKEN_TYPE", "VERIFICATION_REQUIRED", "SETUP_ALREADY_COMPLETED": return http.StatusForbidden case "BAD_REQUEST", "INVALID_USERNAME", "INVALID_EMAIL", "INVALID_PHONE", "WEAK_PASSWORD", "USERNAME_EXISTS", "EMAIL_EXISTS", "PHONE_EXISTS", "USER_ALREADY_EXISTS", "INVALID_OPERATION", "VERIFICATION_CODE_INVALID", "VERIFICATION_CODE_EXPIRED", "EMAIL_ALREADY_VERIFIED", "EMAIL_NOT_BOUND", "GROUP_FULL", "ALREADY_GROUP_MEMBER", "CANNOT_REMOVE_OWNER", "CANNOT_MUTE_OWNER", "CANNOT_JOIN", "JOIN_REQUEST_PENDING", "GROUP_REQUEST_HANDLED", "NOT_REQUEST_TARGET", "NO_ELIGIBLE_INVITEE", "NOT_MUTUAL_FOLLOW", "INVITE_NOT_ACCEPTED", "STICKER_ALREADY_EXISTS", "INVALID_STICKER_URL", "INVALID_SCHEDULE_PAYLOAD", "SCHEDULE_COLOR_DUPLICATED", "INVALID_SETUP_SECRET", "SETUP_SECRET_NOT_CONFIGURED": return http.StatusBadRequest case "VERIFICATION_CODE_TOO_FREQUENT": return http.StatusTooManyRequests case "EMAIL_SERVICE_UNAVAILABLE", "VERIFICATION_CODE_UNAVAILABLE", "INTERNAL_ERROR": return http.StatusInternalServerError default: return http.StatusBadRequest } } // ErrorWithStringCode 带字符串错误码的错误响应 func ErrorWithStringCode(c *gin.Context, statusCode int, code string, message string) { c.JSON(statusCode, gin.H{ "code": statusCode, "message": message, "error_code": code, }) }