-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidation.go
More file actions
136 lines (118 loc) · 3.78 KB
/
Copy pathvalidation.go
File metadata and controls
136 lines (118 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package pluginsdk
import (
"fmt"
"reflect"
"strings"
"github.com/go-playground/validator/v10"
)
// ValidationError represents a field-level validation error
type ValidationError struct {
Field string `json:"field"`
Message string `json:"message"`
}
// ValidationErrors is a collection of validation errors
type ValidationErrors struct {
Errors []ValidationError `json:"errors"`
}
func (v ValidationErrors) Error() string {
var messages []string
for _, err := range v.Errors {
messages = append(messages, fmt.Sprintf("%s: %s", err.Field, err.Message))
}
return strings.Join(messages, "; ")
}
// GetValidator returns a configured validator instance
func GetValidator() *validator.Validate {
v := validator.New(validator.WithRequiredStructEnabled())
// Register custom tag name function to use json tags for field names
v.RegisterTagNameFunc(func(fld reflect.StructField) string {
jsonTag := fld.Tag.Get("json")
if jsonTag == "" {
return ""
}
parts := strings.Split(jsonTag, ",")
return parts[0]
})
return v
}
// ValidateStruct validates a struct and returns user-friendly validation errors
func ValidateStruct(s interface{}) error {
validate := GetValidator()
err := validate.Struct(s)
if err == nil {
return nil
}
validationErrs, ok := err.(validator.ValidationErrors)
if !ok {
return err
}
var errors []ValidationError
for _, e := range validationErrs {
errors = append(errors, ValidationError{
Field: getJSONFieldName(e),
Message: getErrorMessage(e),
})
}
return ValidationErrors{Errors: errors}
}
// getJSONFieldName extracts the JSON field name from the validation error
func getJSONFieldName(e validator.FieldError) string {
namespace := e.Namespace()
// Remove the root struct name (everything before the first dot)
// e.g., "Config.external_links[0].url" -> "external_links[0].url"
parts := strings.SplitN(namespace, ".", 2)
if len(parts) > 1 {
return parts[1]
}
return e.Field()
}
// getErrorMessage converts validator tag to human-readable message
func getErrorMessage(e validator.FieldError) string {
field := getJSONFieldName(e)
switch e.Tag() {
case "required":
return fmt.Sprintf("%s is required", field)
case "required_if":
return fmt.Sprintf("%s is required", field)
case "required_with":
return fmt.Sprintf("%s is required when %s is specified", field, e.Param())
case "min":
if e.Type().Kind() == reflect.String {
return fmt.Sprintf("%s must be at least %s characters", field, e.Param())
}
return fmt.Sprintf("%s must be at least %s", field, e.Param())
case "max":
if e.Type().Kind() == reflect.String {
return fmt.Sprintf("%s must be at most %s characters", field, e.Param())
}
return fmt.Sprintf("%s must be at most %s", field, e.Param())
case "email":
return fmt.Sprintf("%s must be a valid email address", field)
case "url":
return fmt.Sprintf("%s must be a valid URL", field)
case "oneof":
return fmt.Sprintf("%s must be one of: %s", field, e.Param())
case "numeric":
return fmt.Sprintf("%s must be numeric", field)
case "alpha":
return fmt.Sprintf("%s must contain only letters", field)
case "alphanum":
return fmt.Sprintf("%s must contain only letters and numbers", field)
case "gte":
return fmt.Sprintf("%s must be greater than or equal to %s", field, e.Param())
case "gt":
return fmt.Sprintf("%s must be greater than %s", field, e.Param())
case "lte":
return fmt.Sprintf("%s must be less than or equal to %s", field, e.Param())
case "lt":
return fmt.Sprintf("%s must be less than %s", field, e.Param())
case "hostname":
return fmt.Sprintf("%s must be a valid hostname", field)
case "hostname_port":
return fmt.Sprintf("%s must be a valid hostname:port", field)
case "ip":
return fmt.Sprintf("%s must be a valid IP address", field)
default:
return fmt.Sprintf("%s is invalid", field)
}
}