12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- package validation
- import (
- "fmt"
- "reflect"
- "regexp"
- "strings"
- "github.com/go-playground/validator/v10"
- )
- var (
- validate *validator.Validate
- // Common validation patterns
- passwordRegex = regexp.MustCompile(`^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};:'",.<>/?]{8,}$`)
- phoneRegex = regexp.MustCompile(`^\+?[1-9]\d{1,14}$`)
- )
- func init() {
- validate = validator.New()
- // Register custom validation tags
- validate.RegisterValidation("password", validatePassword)
- validate.RegisterValidation("phone", validatePhone)
- // Register custom error messages
- validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
- name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
- if name == "-" {
- return fld.Name
- }
- return name
- })
- }
- // Validate performs validation on the given struct and returns formatted error messages
- func Validate(i interface{}) []ValidationError {
- err := validate.Struct(i)
- if err == nil {
- return nil
- }
- var validationErrors []ValidationError
- for _, err := range err.(validator.ValidationErrors) {
- validationErrors = append(validationErrors, ValidationError{
- Field: err.Field(),
- Message: formatErrorMessage(err),
- })
- }
- return validationErrors
- }
- // ValidationError represents a single validation error
- type ValidationError struct {
- Field string `json:"field"`
- Message string `json:"message"`
- }
- // Custom validators
- func validatePassword(fl validator.FieldLevel) bool {
- return passwordRegex.MatchString(fl.Field().String())
- }
- func validatePhone(fl validator.FieldLevel) bool {
- if fl.Field().String() == "" {
- return true // Phone is optional
- }
- return phoneRegex.MatchString(fl.Field().String())
- }
- // formatErrorMessage returns a user-friendly error message for validation errors
- func formatErrorMessage(err validator.FieldError) string {
- switch err.Tag() {
- case "required":
- return fmt.Sprintf("%s is required", err.Field())
- case "email":
- return fmt.Sprintf("%s must be a valid email address", err.Field())
- case "min":
- return fmt.Sprintf("%s must be at least %s characters long", err.Field(), err.Param())
- case "max":
- return fmt.Sprintf("%s must not exceed %s characters", err.Field(), err.Param())
- case "password":
- return fmt.Sprintf("%s must be at least 8 characters long and contain only letters, numbers, and special characters", err.Field())
- case "phone":
- return fmt.Sprintf("%s must be a valid phone number in E.164 format", err.Field())
- case "uuid":
- return fmt.Sprintf("%s must be a valid UUID", err.Field())
- default:
- return fmt.Sprintf("%s failed validation: %s", err.Field(), err.Tag())
- }
- }
|