- Updated docs ( much more to come ) - v9 is much simpler to use. v8 vs v9 improvements ``` benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-8 118 147 +24.58% BenchmarkFieldFailure-8 758 417 -44.99% BenchmarkFieldDiveSuccess-8 2471 876 -64.55% BenchmarkFieldDiveFailure-8 3172 1185 -62.64% BenchmarkFieldCustomTypeSuccess-8 300 321 +7.00% BenchmarkFieldCustomTypeFailure-8 775 416 -46.32% BenchmarkFieldOrTagSuccess-8 1122 1119 -0.27% BenchmarkFieldOrTagFailure-8 1167 715 -38.73% BenchmarkStructLevelValidationSuccess-8 548 399 -27.19% BenchmarkStructLevelValidationFailure-8 558 749 +34.23% BenchmarkStructSimpleCustomTypeSuccess-8 623 673 +8.03% BenchmarkStructSimpleCustomTypeFailure-8 1381 1056 -23.53% BenchmarkStructPartialSuccess-8 1036 789 -23.84% BenchmarkStructPartialFailure-8 1734 1105 -36.27% BenchmarkStructExceptSuccess-8 888 1212 +36.49% BenchmarkStructExceptFailure-8 1036 1004 -3.09% BenchmarkStructSimpleCrossFieldSuccess-8 773 656 -15.14% BenchmarkStructSimpleCrossFieldFailure-8 1487 968 -34.90% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1261 1000 -20.70% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2055 1324 -35.57% BenchmarkStructSimpleSuccess-8 519 534 +2.89% BenchmarkStructSimpleFailure-8 1429 1039 -27.29% BenchmarkStructSimpleSuccessParallel-8 146 144 -1.37% BenchmarkStructSimpleFailureParallel-8 551 419 -23.96% BenchmarkStructComplexSuccess-8 3269 2678 -18.08% BenchmarkStructComplexFailure-8 8436 6342 -24.82% BenchmarkStructComplexSuccessParallel-8 1024 874 -14.65% BenchmarkStructComplexFailureParallel-8 3536 2875 -18.69% benchmark old allocs new allocs delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 4 4 +0.00% BenchmarkFieldDiveSuccess-8 28 11 -60.71% BenchmarkFieldDiveFailure-8 32 16 -50.00% BenchmarkFieldCustomTypeSuccess-8 2 2 +0.00% BenchmarkFieldCustomTypeFailure-8 4 4 +0.00% BenchmarkFieldOrTagSuccess-8 1 1 +0.00% BenchmarkFieldOrTagFailure-8 6 5 -16.67% BenchmarkStructLevelValidationSuccess-8 5 2 -60.00% BenchmarkStructLevelValidationFailure-8 5 8 +60.00% BenchmarkStructSimpleCustomTypeSuccess-8 3 2 -33.33% BenchmarkStructSimpleCustomTypeFailure-8 9 9 +0.00% BenchmarkStructPartialSuccess-8 9 6 -33.33% BenchmarkStructPartialFailure-8 14 11 -21.43% BenchmarkStructExceptSuccess-8 7 12 +71.43% BenchmarkStructExceptFailure-8 9 10 +11.11% BenchmarkStructSimpleCrossFieldSuccess-8 4 3 -25.00% BenchmarkStructSimpleCrossFieldFailure-8 9 8 -11.11% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 7 4 -42.86% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 12 9 -25.00% BenchmarkStructSimpleSuccess-8 1 0 -100.00% BenchmarkStructSimpleFailure-8 9 9 +0.00% BenchmarkStructSimpleSuccessParallel-8 1 0 -100.00% BenchmarkStructSimpleFailureParallel-8 9 9 +0.00% BenchmarkStructComplexSuccess-8 15 8 -46.67% BenchmarkStructComplexFailure-8 60 53 -11.67% BenchmarkStructComplexSuccessParallel-8 15 8 -46.67% BenchmarkStructComplexFailureParallel-8 60 53 -11.67% benchmark old bytes new bytes delta BenchmarkFieldSuccess-8 0 0 +0.00% BenchmarkFieldFailure-8 432 192 -55.56% BenchmarkFieldDiveSuccess-8 464 201 -56.68% BenchmarkFieldDiveFailure-8 896 396 -55.80% BenchmarkFieldCustomTypeSuccess-8 32 32 +0.00% BenchmarkFieldCustomTypeFailure-8 432 192 -55.56% BenchmarkFieldOrTagSuccess-8 4 16 +300.00% BenchmarkFieldOrTagFailure-8 448 208 -53.57% BenchmarkStructLevelValidationSuccess-8 160 32 -80.00% BenchmarkStructLevelValidationFailure-8 160 288 +80.00% BenchmarkStructSimpleCustomTypeSuccess-8 36 32 -11.11% BenchmarkStructSimpleCustomTypeFailure-8 640 392 -38.75% BenchmarkStructPartialSuccess-8 272 256 -5.88% BenchmarkStructPartialFailure-8 730 464 -36.44% BenchmarkStructExceptSuccess-8 250 480 +92.00% BenchmarkStructExceptFailure-8 272 448 +64.71% BenchmarkStructSimpleCrossFieldSuccess-8 80 72 -10.00% BenchmarkStructSimpleCrossFieldFailure-8 536 288 -46.27% BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 112 80 -28.57% BenchmarkStructSimpleCrossStructCrossFieldFailure-8 576 304 -47.22% BenchmarkStructSimpleSuccess-8 4 0 -100.00% BenchmarkStructSimpleFailure-8 640 392 -38.75% BenchmarkStructSimpleSuccessParallel-8 4 0 -100.00% BenchmarkStructSimpleFailureParallel-8 640 392 -38.75% BenchmarkStructComplexSuccess-8 244 128 -47.54% BenchmarkStructComplexFailure-8 3609 2833 -21.50% BenchmarkStructComplexSuccessParallel-8 244 128 -47.54% BenchmarkStructComplexFailureParallel-8 3609 2833 -21.50% ```pull/256/head
parent
852e5ff9f9
commit
b0883e6ed8
@ -0,0 +1,101 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"gopkg.in/go-playground/validator.v9" |
||||
) |
||||
|
||||
// User contains user information
|
||||
type User struct { |
||||
FirstName string `validate:"required"` |
||||
LastName string `validate:"required"` |
||||
Age uint8 `validate:"gte=0,lte=130"` |
||||
Email string `validate:"required,email"` |
||||
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
|
||||
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
||||
} |
||||
|
||||
// Address houses a users address information
|
||||
type Address struct { |
||||
Street string `validate:"required"` |
||||
City string `validate:"required"` |
||||
Planet string `validate:"required"` |
||||
Phone string `validate:"required"` |
||||
} |
||||
|
||||
// use a single instance of Validate, it caches struct info
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
validate = validator.New() |
||||
|
||||
validateStruct() |
||||
validateVariable() |
||||
} |
||||
|
||||
func validateStruct() { |
||||
|
||||
address := &Address{ |
||||
Street: "Eavesdown Docks", |
||||
Planet: "Persphone", |
||||
Phone: "none", |
||||
} |
||||
|
||||
user := &User{ |
||||
FirstName: "Badger", |
||||
LastName: "Smith", |
||||
Age: 135, |
||||
Email: "Badger.Smith@gmail.com", |
||||
FavouriteColor: "#000-", |
||||
Addresses: []*Address{address}, |
||||
} |
||||
|
||||
// returns nil or ValidationErrors ( map[string]*FieldError )
|
||||
err := validate.Struct(user) |
||||
if err != nil { |
||||
|
||||
// this check is only needed when your code could produce
|
||||
// an invalid value for validation such as interface with nil
|
||||
// value most including myself do not usually have code like this.
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok { |
||||
fmt.Println(err) |
||||
return |
||||
} |
||||
|
||||
for _, err := range err.(validator.ValidationErrors) { |
||||
|
||||
fmt.Println(err.Namespace()) |
||||
fmt.Println(err.Field()) |
||||
fmt.Println(err.StructNamespace()) // can differ when a custom TagNameFunc is registered or
|
||||
fmt.Println(err.StructField()) // by passing alt name to ReportError like below
|
||||
fmt.Println(err.Tag()) |
||||
fmt.Println(err.ActualTag()) |
||||
fmt.Println(err.Kind()) |
||||
fmt.Println(err.Type()) |
||||
fmt.Println(err.Value()) |
||||
fmt.Println(err.Param()) |
||||
fmt.Println() |
||||
} |
||||
|
||||
// from here you can create your own error messages in whatever language you wish
|
||||
return |
||||
} |
||||
|
||||
// save user to database
|
||||
} |
||||
|
||||
func validateVariable() { |
||||
|
||||
myEmail := "joeybloggs.gmail.com" |
||||
|
||||
errs := validate.Var(myEmail, "required,email") |
||||
|
||||
if errs != nil { |
||||
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
|
||||
return |
||||
} |
||||
|
||||
// email ok, move on
|
||||
} |
@ -1,155 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"reflect" |
||||
|
||||
sql "database/sql/driver" |
||||
|
||||
"gopkg.in/go-playground/validator.v8" |
||||
) |
||||
|
||||
// User contains user information
|
||||
type User struct { |
||||
FirstName string `validate:"required"` |
||||
LastName string `validate:"required"` |
||||
Age uint8 `validate:"gte=0,lte=130"` |
||||
Email string `validate:"required,email"` |
||||
FavouriteColor string `validate:"hexcolor|rgb|rgba"` |
||||
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
|
||||
} |
||||
|
||||
// Address houses a users address information
|
||||
type Address struct { |
||||
Street string `validate:"required"` |
||||
City string `validate:"required"` |
||||
Planet string `validate:"required"` |
||||
Phone string `validate:"required"` |
||||
} |
||||
|
||||
var validate *validator.Validate |
||||
|
||||
func main() { |
||||
|
||||
config := &validator.Config{TagName: "validate"} |
||||
|
||||
validate = validator.New(config) |
||||
|
||||
validateStruct() |
||||
validateField() |
||||
} |
||||
|
||||
func validateStruct() { |
||||
|
||||
address := &Address{ |
||||
Street: "Eavesdown Docks", |
||||
Planet: "Persphone", |
||||
Phone: "none", |
||||
} |
||||
|
||||
user := &User{ |
||||
FirstName: "Badger", |
||||
LastName: "Smith", |
||||
Age: 135, |
||||
Email: "Badger.Smith@gmail.com", |
||||
FavouriteColor: "#000", |
||||
Addresses: []*Address{address}, |
||||
} |
||||
|
||||
// returns nil or ValidationErrors ( map[string]*FieldError )
|
||||
errs := validate.Struct(user) |
||||
|
||||
if errs != nil { |
||||
|
||||
fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag
|
||||
// Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag
|
||||
err := errs.(validator.ValidationErrors)["User.Addresses[0].City"] |
||||
fmt.Println(err.Field) // output: City
|
||||
fmt.Println(err.Tag) // output: required
|
||||
fmt.Println(err.Kind) // output: string
|
||||
fmt.Println(err.Type) // output: string
|
||||
fmt.Println(err.Param) // output:
|
||||
fmt.Println(err.Value) // output:
|
||||
|
||||
// from here you can create your own error messages in whatever language you wish
|
||||
return |
||||
} |
||||
|
||||
// save user to database
|
||||
} |
||||
|
||||
func validateField() { |
||||
myEmail := "joeybloggs.gmail.com" |
||||
|
||||
errs := validate.Field(myEmail, "required,email") |
||||
|
||||
if errs != nil { |
||||
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
|
||||
return |
||||
} |
||||
|
||||
// email ok, move on
|
||||
} |
||||
|
||||
var validate2 *validator.Validate |
||||
|
||||
type valuer struct { |
||||
Name string |
||||
} |
||||
|
||||
func (v valuer) Value() (sql.Value, error) { |
||||
|
||||
if v.Name == "errorme" { |
||||
return nil, errors.New("some kind of error") |
||||
} |
||||
|
||||
if v.Name == "blankme" { |
||||
return "", nil |
||||
} |
||||
|
||||
if len(v.Name) == 0 { |
||||
return nil, nil |
||||
} |
||||
|
||||
return v.Name, nil |
||||
} |
||||
|
||||
// ValidateValuerType implements validator.CustomTypeFunc
|
||||
func ValidateValuerType(field reflect.Value) interface{} { |
||||
if valuer, ok := field.Interface().(sql.Valuer); ok { |
||||
val, err := valuer.Value() |
||||
if err != nil { |
||||
// handle the error how you want
|
||||
return nil |
||||
} |
||||
|
||||
return val |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func main2() { |
||||
|
||||
config := &validator.Config{TagName: "validate"} |
||||
|
||||
validate2 = validator.New(config) |
||||
validate2.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{}) |
||||
|
||||
validateCustomFieldType() |
||||
} |
||||
|
||||
func validateCustomFieldType() { |
||||
val := valuer{ |
||||
Name: "blankme", |
||||
} |
||||
|
||||
errs := validate2.Field(val, "required") |
||||
if errs != nil { |
||||
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "required" tag
|
||||
return |
||||
} |
||||
|
||||
// all ok
|
||||
} |
Loading…
Reference in new issue