Documentation ¶
Overview ¶
Package validator enables strongly-typed Validate methods to validate any types.
Builtin Validators ¶
There are builtin validators.
- In
- InRange
- Length
- Max
- MaxLength
- Min
- MinLength
- Pattern
- Required
When these builtin validators detects the value is invalid, they returns just an error corresponding to the validator. In other words, they don't return multiple errors wrapped by errors.Join.
Also there are few composition validators.
- Join
- Slice
- Struct
These validators wraps multiple validators (including composition validators itself), so it could be contained multiple errors to a returned error from them.
To get the details:
// Join validator err := validator.Join(validator.Min(3)).Validate(context.Background(), 2) if e, ok := err.(interface{ Unwrap() []error }); ok { fmt.Println(e.Unwrap()) } // Slice validator v := validator.Slice(validator.Min(3)) err := v.Validate(context.Background(), []int{3, 2, 1}) if e, ok := err.(*validator.SliceError[[]int, int]); ok { fmt.Println(e.Errors) } // Struct validator v := validator.Struct(func(s validator.StructRule, r *Data) { // ... }) err := v.Validate(context.Background(), &Data{}) if e, ok := err.(*validator.StructError[*Data, Data]); ok { fmt.Println(e.Errors) }
Custom validator ¶
The New utility function makes it easy to implement custom validators.
We highly recommend to set custom error message with WithFormat to that validator. It also has default error message but it might be a unsufficient to your users.
Error message ¶
The builtin- and compositon-validators has default error messages. Additionally these validators provides to modify its each default message to appropriate message on the situation.
For example:
v := validator.Min(3).WithFormat("%[1]v is not valid", validator.ByName("value"))
It is different for each the validator to be available argument names with ByName. See each the validator documentation.
Internationalization ¶
The validators error messages are available in multiple languages.
The validator package assumes English is default language. To switch default language to another one, it is set Printer provided by golang.org/x/text/message to ctx that will be passed to the first argument of Validate[T] method.
Example ¶
type ( User struct { ID string Name string } Request struct { User *User Options []string } ) var requestValidator = validator.Struct(func(s validator.StructRule, r *Request) { validator.AddField(s, &r.User, "user", validator.Struct(func(s validator.StructRule, u *User) { validator.AddField(s, &u.ID, "id", validator.Length[string](5, 10)) validator.AddField(s, &u.Name, "name", validator.Required[string]()) })) validator.AddField(s, &r.Options, "options", validator.Slice(validator.In("option1", "option2"))) }) var r Request r.Options = []string{"option3"} err := requestValidator.Validate(context.Background(), &r) fmt.Println(err)
Output: user: name: cannot be the zero value user: id: the length must be in range(5 ... 10) options: must be a valid value in [option1 option2]
Example (CustomMessage) ¶
package main import ( "context" "fmt" "github.com/lufia/go-validator" "golang.org/x/text/language" "golang.org/x/text/message" ) func init() { message.SetString(language.English, "must be of length %[1]d to %[2]d", "must be of length %[1]d to %[2]d") message.SetString(language.Japanese, "must be of length %[1]d to %[2]d", "%[1]d文字以上%[2]d文字以内で入力してください") } func main() { type Data struct { Num int Name string } v := validator.Struct(func(s validator.StructRule, r *Data) { validator.AddField(s, &r.Name, "name", validator.Length[string](3, 100).WithFormat("must be of length %[1]d to %[2]d", validator.ByName("min"), validator.ByName("max")), ) }) p := message.NewPrinter(language.English) ctx := validator.WithPrinter(context.Background(), p) err := v.Validate(ctx, &Data{ Num: 10, Name: "xx", }) fmt.Println(err) }
Output: name: must be of length 3 to 100
Example (CustomValidator) ¶
package main import ( "context" "fmt" "strings" "github.com/lufia/go-validator" ) type CreateUserRequest struct { Name string Password string ConfirmationPassword string } var ( usernameValidator = validator.New(func(v string) bool { // find non-alnum or non-ascii character i := strings.IndexFunc(v, func(c rune) bool { switch { default: return true case c >= 'a' && c <= 'z': return false case c >= 'A' && c <= 'Z': return false case c >= '0' && c <= '9': return false } }) return i < 0 }).WithFormat("does not allow not-alphabets or not-digits") passwordValidator = validator.New(func(r *CreateUserRequest) bool { return r.Password == r.ConfirmationPassword }).WithFormat("passwords does not match") ) var createUserRequestValidator = validator.Join( validator.Struct(func(s validator.StructRule, r *CreateUserRequest) { validator.AddField(s, &r.Name, "name", validator.Length[string](5, 20), usernameValidator) validator.AddField(s, &r.Password, "password", validator.MinLength[string](8)) validator.AddField(s, &r.ConfirmationPassword, "confirmation-password", validator.MinLength[string](8)) }), passwordValidator, ) func main() { ctx := context.Background() err := createUserRequestValidator.Validate(ctx, &CreateUserRequest{ Name: ".adm", Password: "1234", ConfirmationPassword: "abcd", }) fmt.Println(err) }
Output: name: the length must be in range(5 ... 20) name: does not allow not-alphabets or not-digits password: the length must be no less than 8 confirmation-password: the length must be no less than 8 passwords does not match
Example (Localized) ¶
type ( User struct { ID string Name string } Request struct { User *User Options []string } ) var requestValidator = validator.Struct(func(s validator.StructRule, r *Request) { validator.AddField(s, &r.User, "user", validator.Struct(func(s validator.StructRule, u *User) { validator.AddField(s, &u.ID, "id", validator.Length[string](5, 10)) validator.AddField(s, &u.Name, "name", validator.Required[string]()) })) validator.AddField(s, &r.Options, "options", validator.Slice(validator.In("option1", "option2"))) }) p := message.NewPrinter(language.Japanese, message.Catalog(validator.DefaultCatalog)) ctx := validator.WithPrinter(context.Background(), p) var r Request r.Options = []string{"option3"} err := requestValidator.Validate(ctx, &r) fmt.Println(err)
Output: user: name: 必須です user: id: 長さは5以上10以内の制限があります options: [option1 option2]のいずれかでなければなりません
Example (Separated) ¶
type ( User struct { ID string Name string } Request struct { User *User Options []string } ) var ( userValidator = validator.Struct(func(s validator.StructRule, u *User) { validator.AddField(s, &u.ID, "id", validator.Length[string](5, 10)) validator.AddField(s, &u.Name, "name", validator.Required[string]()) }) requestValidator = validator.Struct(func(s validator.StructRule, r *Request) { validator.AddField(s, &r.User, "user", userValidator) validator.AddField(s, &r.Options, "options", validator.Slice( validator.In("option1", "option2"), )) validator.AddField(s, &r.Options, "options", validator.Slice( validator.In("option1", "option2"), )) }) ) var r Request err := requestValidator.Validate(context.Background(), &r) fmt.Println(err)
Output: user: name: cannot be the zero value user: id: the length must be in range(5 ... 10)
Index ¶
- Variables
- func AddField[T any](s StructRule, p *T, name string, vs ...Validator[T])
- func WithPrinter(ctx context.Context, p Printer) context.Context
- type Arg
- type Error
- type OrderedMap
- type Printer
- type SliceError
- type StructError
- type StructRule
- type Validator
- func In[T comparable](a ...T) Validator[T]
- func InRange[T ordered](min, max T) Validator[T]
- func Join[T any](vs ...Validator[T]) Validator[T]
- func Length[T ~string](min, max int) Validator[T]
- func Max[T ordered](n T) Validator[T]
- func MaxLength[T ~string](n int) Validator[T]
- func Min[T ordered](n T) Validator[T]
- func MinLength[T ~string](n int) Validator[T]
- func New[T any](fn func(v T) bool) Validator[T]
- func Pattern[T ~string](re *regexp.Regexp) Validator[T]
- func PatternString[T ~string](pattern string) Validator[T]
- func Required[T comparable]() Validator[T]
- func Slice[T any](vs ...Validator[T]) Validator[[]T]
- func Struct[P ~*T, T any](build func(s StructRule, p P)) Validator[P]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var (
DefaultCatalog = catalog.NewBuilder(catalog.Fallback(defaultLanguage))
)
Functions ¶
Types ¶
type OrderedMap ¶
type OrderedMap[K comparable, V any] struct { // contains filtered or unexported fields }
OrderedMap is a map that guarantee that the iteration order of entries will be the order in which they were set.
func (*OrderedMap[K, V]) Get ¶
func (m *OrderedMap[K, V]) Get(key K) (V, bool)
Get returns a value associated to key.
func (*OrderedMap[K, V]) Keys ¶
func (m *OrderedMap[K, V]) Keys() []K
Keys returns keys of m. These keys preserves the order in which they were set.
type SliceError ¶
type SliceError[S ~[]T, T any] struct { Value S Errors *OrderedMap[int, error] }
SliceError reports an error is caused in Slice validator.
func (SliceError[S, T]) Error ¶
func (e SliceError[S, T]) Error() string
Error implements the error interface.
func (SliceError[S, T]) Unwrap ¶
func (e SliceError[S, T]) Unwrap() []error
Unwrap returns each errors of err.
type StructError ¶
StructError reports an error is caused in Struct validator.
func (StructError[P, T]) Error ¶
func (e StructError[P, T]) Error() string
Error implements the error interface.
func (StructError[P, T]) Unwrap ¶
func (e StructError[P, T]) Unwrap() []error
Unwrap returns each errors of err.
type StructRule ¶
type StructRule interface {
// contains filtered or unexported methods
}
StructRule is the interface to add its fields.
type Validator ¶
type Validator[T any] interface { Validate(ctx context.Context, v T) error WithFormat(key message.Reference, a ...Arg) Validator[T] }
Validator is the interface that wraps the basic Validate method.
func In ¶
func In[T comparable](a ...T) Validator[T]
In returns the validator to verify the value is in a.
Two named args are available in its error format.
- validValues: specified valid values (type []T)
- value: user input (type T)
func InRange ¶
func InRange[T ordered](min, max T) Validator[T]
InRange returns the validator to verify the value is within min and max.
Three named args are available in its error format.
- min: specified min value (type T)
- max: specified max value (type T)
- value: user input (type T)
func Length ¶
Length returns the validator to verify the length of the value is within min and max.
Three named args are available in its error format.
- min: specified min value (type int)
- max: specified max value (type int)
- value: user input (type T)
func Max ¶
func Max[T ordered](n T) Validator[T]
Max returns the validator to verify the value is less or equal than n.
Two named args are available in its error format.
- max: specified max value (type T)
- value: user input (type T)
func MaxLength ¶
MaxLength returns the validator to verify the length of the value is less or equal than n.
Two named args are available in its error format.
- max: specified max value (type int)
- value: user input (type T)
func Min ¶
func Min[T ordered](n T) Validator[T]
Min returns the validator to verify the value is greater or equal than n.
Two named args are available in its error format.
- min: specified min value (type T)
- value: user input (type T)
func MinLength ¶
MinLength returns the validator to verify the length of the value is greater or equal than n.
Two named args are available in its error format.
- min: specified min value (type int)
- value: user input (type T)
func New ¶
New returns the validator to verify the value with fn. If fn returns false, the validator results as error.
A named args is available in its error format.
- value: user input (type T)
func Pattern ¶
Pattern returns the validator to verify the value matches re.
Two named args are available in its error format.
- pattern: specific regular expression (type *regexp.Regexp)
- value: user input (type T)
func PatternString ¶
PatternString returns the validator to verify the value matches pattern.
When pattern is invalid, PatternString panics.
func Required ¶
func Required[T comparable]() Validator[T]
Required returns the validator to verify the value is not zero value.
A named arg is available in its error format.
- value: user input (type T)
func Struct ¶
func Struct[P ~*T, T any](build func(s StructRule, p P)) Validator[P]
Struct returns the validator to verify that the struct satisfies rules constrated with build.
Three named args are available in its error format.
- name: the registered field name (type string)
- value: user input
- error: occurred validation error(s) (type error)