Harden local runtime safety and error handling
This commit is contained in:
73
internal/handlers/respond.go
Normal file
73
internal/handlers/respond.go
Normal file
@@ -0,0 +1,73 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user