forked from go-validator/validator
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdoc.go
202 lines (159 loc) · 6.45 KB
/
doc.go
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Package validator implements value validations
//
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package validator implements value validations based on struct tags.
In code it is often necessary to validate that a given value is valid before
using it for something. A typical example might be something like this.
if age < 18 {
return error.New("age cannot be under 18")
}
This is a simple enough example, but it can get significantly more complex,
especially when dealing with structs.
l := len(strings.Trim(s.Username))
if l < 3 || l > 40 || !regexp.MatchString("^[a-zA-Z]$", s.Username) || s.Age < 18 || s.Password {
return errors.New("Invalid request")
}
You get the idea. Package validator allows one to define valid values as
struct tags when defining a new struct type.
type NewUserRequest struct {
Username string `validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`
Name string `validate:"nonzero"`
Age int `validate:"min=18"`
Password string `validate:"min=8"`
}
Then validating a variable of type NewUserRequest becomes trivial.
r := NewUserRequest{Username: "something", ...}
if errs := walidator.Validate(r); errs != nil {
// do something
}
Builtin validator functions
Here is the list of validator functions builtin in the package.
len
For numeric numbers, len will simply make sure that the value is
equal to the parameter given. For strings, it checks that
the string length is exactly that number of characters. For slices,
arrays, and maps, validates the number of items. (Usage: len=10)
max
For numeric numbers, max will simply make sure that the value is
lesser or equal to the parameter given. For strings, it checks that
the string length is at most that number of characters. For slices,
arrays, and maps, validates the number of items. (Usage: max=10)
min
For numeric numbers, min will simply make sure that the value is
greater or equal to the parameter given. For strings, it checks that
the string length is at least that number of characters. For slices,
arrays, and maps, validates the number of items. (Usage: min=10)
nonzero
This validates that the value is not zero. The appropriate zero value
is given by the Go spec (e.g. for int it's 0, for string it's "", for
pointers is nil, etc.) Usage: nonzero
required
For pointer and interface types, this validates that the value
is non-nil.
regexp
Only valid for string types, it will validate that the value matches
the regular expression provided as parameter. (Usage: regexp=^a.*b$)
uuid
This validates that the string value is a valid RFC 4122 UUID.
latitude
This validates that a float64 or string value contains a valid
geographical latitude value (between -90 and 90 degrees)
longitude
This validates that a float64 or string value contains a valid
geographical longitude value (between -180 and 180 degrees).
Note that there are no tests to prevent conflicting validator parameters. For
instance, these fields will never be valid.
...
A int `validate:"max=0,min=1"`
B string `validate:"len=10,regexp=^$"
...
Multiple validators
You may often need to have a different set of validation
rules for different situations. The global default validator
cannot be changed (to avoid global name clashes) but
you can create custom Validator instances by calling
walidator.New.
You can add your own custom validation functions to
a Validator instance and you can also change the struct
field tag that's recognized from the default "validate" tag.
Custom validation functions
It is possible to add your own custom validation functions with AddValidation.
Note that the validation function is passed the actual type that will be used
when validating. This enables it to create a specialized function
for the type and parameter, and to return an early error when the type is known
to be incorrect.
// notZZ defines a validation function that checks that
// a string value is not "ZZ"
func notZZ(t reflect.Type, param string) (walidator.ValidationFunc, error) {
if t.Kind() != reflect.String {
return nil, fmt.Errorf("unsupported type")
}
return func(v reflect.Value, r *walidator.ErrorReporter) {
if v.String() == "ZZ" {
r.Errorf("value cannot be ZZ")
}
}, nil
}
Then one needs to add it to the list of validation funcs and give it a "tag" name.
v := walidator.New()
v.AddValidation("notzz", notZZ)
Then it is possible to use the notzz validation tag. This will print
"validation error: A: value cannot be ZZ"
type T struct {
A string `validate:"nonzero,notzz"`
}
t := T{"ZZ"}
if err := v.Validate(t); err != nil {
fmt.Printf("validation error: %v\n", err)
}
If you wish to parameterize the tag, you can use the parameter
argument to the validator, which holds the string after the "="
in the struct tag.
// notSomething defines a validation function that checks that
// a string value is not equal to its parameter.
func notSomething(t reflect.Type, param string) (walidator.ValidationFunc, error) {
if t.Kind() != reflect.String {
return nil, fmt.Errorf("unsupported type")
}
return func(v reflect.Value, r *walidator.ErrorReporter) {
if v.String() == param {
r.Errorf("value cannot be %q", param)
}
}, nil
}
And then the code below should print "validation error: A: value cannot be ABC".
v.AddValidation("notsomething", notSomething)
type T struct {
A string `validate:"notsomething=ABC"`
}
t := T{"ABC"}
if err := v.Validate(t); err != nil {
fmt.Printf("validation error: %v\n", err)
}
Using an unknown validation func in a field tag will cause Validate to return
a validation error.
Custom tag name
There might be a reason not to use the tag 'validate' (maybe due to
a conflict with a different package). In this case, you can
create a new Validator instance that will use a different tag:
v := walidator.New().WithTag("valid")
Then.
Type T struct {
A int `valid:"min=8, max=10"`
B string `valid:"nonzero"`
}
*/
package walidator