package apperr import ( "errors" "log" "net/http" "strings" "github.com/gin-gonic/gin" ) func Middleware(c *gin.Context) { c.Next() if len(c.Errors) > 0 { // Failsafe default response response := ErrorResponse{ Error: ErrorDetail{ Code: http.StatusInternalServerError, Message: "Internal Server Error", }, } // Iterate over all errors so none are lost in the logs for _, ginErr := range c.Errors { actualErr := ginErr.Err var appErr *Error if errors.As(actualErr, &appErr) { // We continually overwrite the response, so the final client response is the last error added response.Error.Code = appErr.Code response.Error.Message = appErr.Message response.Error.Details = appErr.Details appErr.Log(c) } else { if c.Writer.Status() != http.StatusOK { response.Error.Code = c.Writer.Status() response.Error.Message = http.StatusText(c.Writer.Status()) } internalErrStr := strings.ReplaceAll(actualErr.Error(), "\n", " ") log.Printf("\033[31m[UNHANDLED ERROR]\033[0m %s %s - %s\n", c.Request.Method, c.Request.URL.Path, internalErrStr) } } // Send formatted JSON for the last error encountered if !c.Writer.Written() { c.JSON(response.Error.Code, response) } // Empty the backpack to prevent Gin from duplicating logs via its internal logger c.Errors = nil } }