template-monorepo/internal/library/validate/errors.go

70 lines
1.9 KiB
Go

package validate
import (
"errors"
"fmt"
"strings"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
errs "gateway/internal/library/errors"
"gateway/internal/library/errors/code"
)
// ValidationError holds information about a single validation error.
type ValidationError struct {
Field string `json:"field"`
Message string `json:"message"`
}
// ValidationErrors is a slice of ValidationError that implements the error interface.
type ValidationErrors []ValidationError
func (ve ValidationErrors) Error() string {
if len(ve) == 0 {
return ""
}
var sb strings.Builder
sb.WriteString("validation failed:")
for i, e := range ve {
fmt.Fprintf(&sb, " field='%s', message='%s'", e.Field, e.Message)
if i < len(ve)-1 {
sb.WriteString(";")
}
}
return sb.String()
}
// Is supports errors.Is when comparing against ValidationErrors.
func (ValidationErrors) Is(target error) bool {
_, ok := target.(ValidationErrors)
return ok
}
// AsErrors unwraps err into ValidationErrors when present.
func AsErrors(err error) (ValidationErrors, bool) {
var ve ValidationErrors
if errors.As(err, &ve) {
return ve, true
}
return nil, false
}
// ToBusinessError maps field validation failures to InputInvalidFormat (HTTP 400).
func (ve ValidationErrors) ToBusinessError(scope code.Scope) *errs.Error {
return errs.For(scope).InputInvalidFormat(ve.Error())
}
// translateValidationErrors converts validator.ValidationErrors to our custom ValidationErrors.
func translateValidationErrors(valErrs validator.ValidationErrors, trans ut.Translator) ValidationErrors {
customErrors := make(ValidationErrors, 0, len(valErrs))
for _, err := range valErrs {
customErrors = append(customErrors, ValidationError{
Field: err.Field(), // Already transformed by RegisterTagNameFunc
Message: err.Translate(trans),
})
}
return customErrors
}