package handlers import ( "encoding/json" "errors" "io" "strings" "github.com/gin-gonic/gin" ) func RespondError(c *gin.Context, status int, fallback string, err error) { if err != nil { _ = c.Error(err) } c.JSON(status, gin.H{"error": clientFacingErrorMessage(status, fallback, err)}) } func clientFacingErrorMessage(status int, fallback string, err error) string { if err == nil { return fallback } if status >= 500 { return fallback } if isRequestDecodeError(err) { return fallback } message := strings.TrimSpace(err.Error()) if message == "" { return fallback } if looksTechnicalError(message) { return fallback } return message } func isRequestDecodeError(err error) bool { var syntaxErr *json.SyntaxError if errors.As(err, &syntaxErr) { return true } var unmarshalTypeErr *json.UnmarshalTypeError if errors.As(err, &unmarshalTypeErr) { return true } return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) } func looksTechnicalError(message string) bool { lower := strings.ToLower(strings.TrimSpace(message)) needles := []string{ "sql", "gorm", "driver", "constraint", "syntax error", "unexpected eof", "record not found", "no such table", "stack trace", } for _, needle := range needles { if strings.Contains(lower, needle) { return true } } return false }