1
|
|
|
// Copyright 2021 Igor Lazarev. All rights reserved. |
2
|
|
|
// Use of this source code is governed by a MIT-style |
3
|
|
|
// license that can be found in the LICENSE file. |
4
|
|
|
|
5
|
|
|
// Package validator contains Validator service singleton. |
6
|
|
|
// It can be used in a custom application to perform the validation process. |
7
|
|
|
package validator |
8
|
|
|
|
9
|
|
|
import ( |
10
|
|
|
"context" |
11
|
|
|
"time" |
12
|
|
|
|
13
|
|
|
"github.com/muonsoft/validation" |
14
|
|
|
"golang.org/x/text/language" |
15
|
|
|
) |
16
|
|
|
|
17
|
|
|
var validator, _ = validation.NewValidator() |
18
|
|
|
|
19
|
|
|
// SetOptions can be used to set up a singleton validator. Make sure you call this function once |
20
|
|
|
// at the initialization of your application. |
21
|
|
|
func SetOptions(options ...validation.ValidatorOption) error { |
22
|
1 |
|
for _, setOption := range options { |
23
|
1 |
|
err := setOption(validator) |
24
|
1 |
|
if err != nil { |
25
|
|
|
return err |
26
|
|
|
} |
27
|
|
|
} |
28
|
|
|
|
29
|
1 |
|
return nil |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
// Reset function recreates singleton validator. Generally, it can be used in tests. |
33
|
|
|
func Reset() { |
34
|
1 |
|
validator, _ = validation.NewValidator() |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
// Validate is the main validation method. It accepts validation arguments. Arguments can be |
38
|
|
|
// used to tune up the validation process or to pass values of a specific type. |
39
|
|
|
func Validate(arguments ...validation.Argument) error { |
40
|
1 |
|
return validator.Validate(arguments...) |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
// ValidateValue is an alias for validating a single value of any supported type. |
44
|
|
|
func ValidateValue(value interface{}, options ...validation.Option) error { |
45
|
1 |
|
return validator.ValidateValue(value, options...) |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
// ValidateBool is an alias for validating a single boolean value. |
49
|
|
|
func ValidateBool(value *bool, options ...validation.Option) error { |
50
|
1 |
|
return validator.ValidateBool(value, options...) |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
// ValidateNumber is an alias for validating a single numeric value (integer or float). |
54
|
|
|
func ValidateNumber(value interface{}, options ...validation.Option) error { |
55
|
1 |
|
return validator.ValidateNumber(value, options...) |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
// ValidateString is an alias for validating a single string value. |
59
|
|
|
func ValidateString(value *string, options ...validation.Option) error { |
60
|
1 |
|
return validator.ValidateString(value, options...) |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
// ValidateIterable is an alias for validating a single iterable value (an array, slice, or map). |
64
|
|
|
func ValidateIterable(value interface{}, options ...validation.Option) error { |
65
|
1 |
|
return validator.ValidateIterable(value, options...) |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
// ValidateCountable is an alias for validating a single countable value (an array, slice, or map). |
69
|
|
|
func ValidateCountable(count int, options ...validation.Option) error { |
70
|
1 |
|
return validator.ValidateCountable(count, options...) |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
// ValidateTime is an alias for validating a single time value. |
74
|
|
|
func ValidateTime(value *time.Time, options ...validation.Option) error { |
75
|
1 |
|
return validator.ValidateTime(value, options...) |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
// ValidateEach is an alias for validating each value of an iterable (an array, slice, or map). |
79
|
|
|
func ValidateEach(value interface{}, options ...validation.Option) error { |
80
|
1 |
|
return validator.ValidateEach(value, options...) |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
// ValidateEachString is an alias for validating each value of a strings slice. |
84
|
|
|
func ValidateEachString(strings []string, options ...validation.Option) error { |
85
|
1 |
|
return validator.ValidateEachString(strings, options...) |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
// ValidateValidatable is an alias for validating value that implements the Validatable interface. |
89
|
|
|
func ValidateValidatable(validatable validation.Validatable, options ...validation.Option) error { |
90
|
1 |
|
return validator.ValidateValidatable(validatable, options...) |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
// WithContext method creates a new scoped validator with a given context. You can use this method to pass |
94
|
|
|
// a context value to all used constraints. |
95
|
|
|
|
96
|
|
|
// Example |
97
|
|
|
// err := validator.WithContext(request.Context()).Validate( |
98
|
|
|
// String(&s, it.IsNotBlank()), // now all called constraints will use passed context in their methods |
99
|
|
|
// ) |
100
|
|
|
func WithContext(ctx context.Context) *validation.Validator { |
101
|
|
|
return validator.WithContext(ctx) |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
// WithLanguage method creates a new scoped validator with a given language tag. All created violations |
105
|
|
|
// will be translated into this language. |
106
|
|
|
// |
107
|
|
|
// Example |
108
|
|
|
// err := validator.WithLanguage(language.Russian).Validate( |
109
|
|
|
// validation.ValidateString(&s, it.IsNotBlank()), // violation from this constraint will be translated |
110
|
|
|
// ) |
111
|
|
|
func WithLanguage(tag language.Tag) *validation.Validator { |
112
|
|
|
return validator.WithLanguage(tag) |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
// AtProperty method creates a new scoped validator with injected property name element to scope property path. |
116
|
|
|
func AtProperty(name string) *validation.Validator { |
117
|
1 |
|
return validator.AtProperty(name) |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
// AtIndex method creates a new scoped validator with injected array index element to scope property path. |
121
|
|
|
func AtIndex(index int) *validation.Validator { |
122
|
1 |
|
return validator.AtIndex(index) |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
// BuildViolation can be used to build a custom violation on the client-side. |
126
|
|
|
// |
127
|
|
|
// Example |
128
|
|
|
// err := validator.BuildViolation("", ""). |
129
|
|
|
// AddParameter("key", "value"). |
130
|
|
|
// CreateViolation() |
131
|
|
|
func BuildViolation(code, message string) *validation.ViolationBuilder { |
132
|
1 |
|
return validator.BuildViolation(code, message) |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
// StoreConstraint can be used to store a constraint in an internal validator store. |
136
|
|
|
// It can later be used by the ValidateBy method. This can be useful for passing |
137
|
|
|
// custom or prepared constraints to Validatable. |
138
|
|
|
// |
139
|
|
|
// If the constraint already exists, a ConstraintAlreadyStoredError is returned. |
140
|
|
|
// |
141
|
|
|
// Due to the fact that the store is a state element, it is strongly recommended |
142
|
|
|
// to fill the store during application initialization to avoid unexpected problems. |
143
|
|
|
// |
144
|
|
|
// Example |
145
|
|
|
// err := validator.StoreConstraint("isTagExists", isTagExistsConstraint) |
146
|
|
|
// if err != nil { |
147
|
|
|
// log.Fatal(err) |
148
|
|
|
// } |
149
|
|
|
// |
150
|
|
|
// s := " |
151
|
|
|
// err = validator.ValidateString(&s, validator.ValidateBy("isTagExists")) |
152
|
|
|
func StoreConstraint(key string, constraint validation.Constraint) error { |
153
|
1 |
|
return validator.StoreConstraint(key, constraint) |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
// ValidateBy is used to get the constraint from the internal validator store. |
157
|
|
|
// If the constraint does not exist, then the validator will |
158
|
|
|
// return a ConstraintNotFoundError during the validation process. |
159
|
|
|
// For storing a constraint you should use the StoreConstraint method. |
160
|
|
|
func ValidateBy(constraintKey string) validation.Constraint { |
161
|
1 |
|
return validator.ValidateBy(constraintKey) |
162
|
|
|
} |
163
|
|
|
|