// Package response is the single source of truth for every JSON // response edgeguard-api emits. Enforces the envelope contract // // {"data": , "error": null | "", "message": ""} // // (1:1 mail-gateway/internal/handlers/response/) so external clients // and the management UI can deserialise into a generic ApiResponse // without per-endpoint special-casing. package response import ( "errors" "net/http" "github.com/gin-gonic/gin" ) type Envelope struct { Data any `json:"data"` Error *string `json:"error"` Message string `json:"message"` } func OK(c *gin.Context, data any) { c.JSON(http.StatusOK, Envelope{Data: data, Error: nil, Message: "OK"}) } func OKWithMessage(c *gin.Context, data any, message string) { c.JSON(http.StatusOK, Envelope{Data: data, Error: nil, Message: message}) } func Created(c *gin.Context, data any) { c.JSON(http.StatusCreated, Envelope{Data: data, Error: nil, Message: "Created"}) } func Accepted(c *gin.Context, data any) { c.JSON(http.StatusAccepted, Envelope{Data: data, Error: nil, Message: "Accepted"}) } func NoContent(c *gin.Context) { c.Status(http.StatusNoContent) } func Err(c *gin.Context, status int, err error) { msg := "" if err != nil { msg = err.Error() } c.JSON(status, Envelope{Data: nil, Error: &msg, Message: msg}) } func ErrMessage(c *gin.Context, status int, err error, message string) { e := "" if err != nil { e = err.Error() } c.JSON(status, Envelope{Data: nil, Error: &e, Message: message}) } func BadRequest(c *gin.Context, err error) { Err(c, http.StatusBadRequest, err) } func NotFound(c *gin.Context, err error) { if err == nil { err = errors.New("not found") } Err(c, http.StatusNotFound, err) } func Unauthorized(c *gin.Context, err error) { if err == nil { err = errors.New("not authenticated") } Err(c, http.StatusUnauthorized, err) } func Forbidden(c *gin.Context, err error) { if err == nil { err = errors.New("forbidden") } Err(c, http.StatusForbidden, err) } func Internal(c *gin.Context, err error) { Err(c, http.StatusInternalServerError, err) }