|
|
@ -1,6 +1,7 @@ |
|
|
|
package main |
|
|
|
package main |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
|
|
|
|
"encoding/json" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"reflect" |
|
|
|
"reflect" |
|
|
|
"strings" |
|
|
|
"strings" |
|
|
@ -8,6 +9,36 @@ import ( |
|
|
|
"github.com/go-playground/validator/v10" |
|
|
|
"github.com/go-playground/validator/v10" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type validationError struct { |
|
|
|
|
|
|
|
Namespace string `json:"namespace"` // can differ when a custom TagNameFunc is registered or
|
|
|
|
|
|
|
|
Field string `json:"field"` // by passing alt name to ReportError like below
|
|
|
|
|
|
|
|
StructNamespace string `json:"structNamespace"` |
|
|
|
|
|
|
|
StructField string `json:"structField"` |
|
|
|
|
|
|
|
Tag string `json:"tag"` |
|
|
|
|
|
|
|
ActualTag string `json:"actualTag"` |
|
|
|
|
|
|
|
Kind string `json:"kind"` |
|
|
|
|
|
|
|
Type string `json:"type"` |
|
|
|
|
|
|
|
Value string `json:"value"` |
|
|
|
|
|
|
|
Param string `json:"param"` |
|
|
|
|
|
|
|
Message string `json:"message"` |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Gender uint |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
Male Gender = iota + 1 |
|
|
|
|
|
|
|
Female |
|
|
|
|
|
|
|
Intersex |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (gender Gender) String() string { |
|
|
|
|
|
|
|
terms := []string{"Male", "Female", "Intersex"} |
|
|
|
|
|
|
|
if gender < Male || gender > Intersex { |
|
|
|
|
|
|
|
return "unknown" |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return terms[gender] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// User contains user information
|
|
|
|
// User contains user information
|
|
|
|
type User struct { |
|
|
|
type User struct { |
|
|
|
FirstName string `json:"fname"` |
|
|
|
FirstName string `json:"fname"` |
|
|
@ -16,6 +47,7 @@ type User struct { |
|
|
|
Email string `json:"e-mail" validate:"required,email"` |
|
|
|
Email string `json:"e-mail" validate:"required,email"` |
|
|
|
FavouriteColor string `validate:"hexcolor|rgb|rgba"` |
|
|
|
FavouriteColor string `validate:"hexcolor|rgb|rgba"` |
|
|
|
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
|
|
|
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
|
|
|
|
|
|
|
Gender Gender `json:"gender" validate:"required,gender_custom_validation"` |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Address houses a users address information
|
|
|
|
// Address houses a users address information
|
|
|
@ -47,6 +79,17 @@ func main() { |
|
|
|
// internally dereferences during it's type checks.
|
|
|
|
// internally dereferences during it's type checks.
|
|
|
|
validate.RegisterStructValidation(UserStructLevelValidation, User{}) |
|
|
|
validate.RegisterStructValidation(UserStructLevelValidation, User{}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// register a custom validation for user genre on a line
|
|
|
|
|
|
|
|
// validates that an enum is within the interval
|
|
|
|
|
|
|
|
err := validate.RegisterValidation("gender_custom_validation", func(fl validator.FieldLevel) bool { |
|
|
|
|
|
|
|
value := fl.Field().Interface().(Gender) |
|
|
|
|
|
|
|
return value.String() != "unknown" |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// build 'User' info, normally posted data etc...
|
|
|
|
// build 'User' info, normally posted data etc...
|
|
|
|
address := &Address{ |
|
|
|
address := &Address{ |
|
|
|
Street: "Eavesdown Docks", |
|
|
|
Street: "Eavesdown Docks", |
|
|
@ -65,7 +108,7 @@ func main() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError )
|
|
|
|
// returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError )
|
|
|
|
err := validate.Struct(user) |
|
|
|
err = validate.Struct(user) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
|
|
|
|
// this check is only needed when your code could produce
|
|
|
|
// this check is only needed when your code could produce
|
|
|
@ -77,18 +120,27 @@ func main() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for _, err := range err.(validator.ValidationErrors) { |
|
|
|
for _, err := range err.(validator.ValidationErrors) { |
|
|
|
|
|
|
|
e := validationError{ |
|
|
|
fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or
|
|
|
|
Namespace: err.Namespace(), |
|
|
|
fmt.Println(err.Field()) // by passing alt name to ReportError like below
|
|
|
|
Field: err.Field(), |
|
|
|
fmt.Println(err.StructNamespace()) |
|
|
|
StructNamespace: err.StructNamespace(), |
|
|
|
fmt.Println(err.StructField()) |
|
|
|
StructField: err.StructField(), |
|
|
|
fmt.Println(err.Tag()) |
|
|
|
Tag: err.Tag(), |
|
|
|
fmt.Println(err.ActualTag()) |
|
|
|
ActualTag: err.ActualTag(), |
|
|
|
fmt.Println(err.Kind()) |
|
|
|
Kind: fmt.Sprintf("%v", err.Kind()), |
|
|
|
fmt.Println(err.Type()) |
|
|
|
Type: fmt.Sprintf("%v", err.Type()), |
|
|
|
fmt.Println(err.Value()) |
|
|
|
Value: fmt.Sprintf("%v", err.Value()), |
|
|
|
fmt.Println(err.Param()) |
|
|
|
Param: err.Param(), |
|
|
|
fmt.Println() |
|
|
|
Message: err.Error(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
indent, err := json.MarshalIndent(e, "", " ") |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
fmt.Println(err) |
|
|
|
|
|
|
|
panic(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fmt.Println(string(indent)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// from here you can create your own error messages in whatever language you wish
|
|
|
|
// from here you can create your own error messages in whatever language you wish
|
|
|
|