Skip to content

Commit 41b4a43

Browse files
joeybloggsjoeybloggs
authored andcommitted
Updated documentation for new v6
1 parent 933fe0b commit 41b4a43

File tree

6 files changed

+192
-273
lines changed

6 files changed

+192
-273
lines changed

README.md

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ Package validator
22
================
33

44
[![Join the chat at https://gitter.im/bluesuncorp/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bluesuncorp/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5-
[![Build Status](https://travis-ci.org/bluesuncorp/validator.svg?branch=v5.1)](https://travis-ci.org/bluesuncorp/validator)
6-
[![Coverage Status](https://coveralls.io/repos/bluesuncorp/validator/badge.svg?branch=v5)](https://coveralls.io/r/bluesuncorp/validator?branch=v5)
7-
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v5?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v5)
5+
[![Build Status](https://travis-ci.org/bluesuncorp/validator.svg?branch=v6)](https://travis-ci.org/bluesuncorp/validator)
6+
[![Coverage Status](https://coveralls.io/repos/bluesuncorp/validator/badge.svg?branch=v6)](https://coveralls.io/r/bluesuncorp/validator?branch=v6)
7+
[![GoDoc](https://godoc.org/gopkg.in/bluesuncorp/validator.v6?status.svg)](https://godoc.org/gopkg.in/bluesuncorp/validator.v6)
88

99
Package validator implements value validations for structs and individual fields based on tags.
1010

@@ -19,20 +19,20 @@ Installation
1919

2020
Use go get.
2121

22-
go get gopkg.in/bluesuncorp/validator.v5
22+
go get gopkg.in/bluesuncorp/validator.v6
2323

2424
or to update
2525

26-
go get -u gopkg.in/bluesuncorp/validator.v5
26+
go get -u gopkg.in/bluesuncorp/validator.v6
2727

2828
Then import the validator package into your own code.
2929

30-
import "gopkg.in/bluesuncorp/validator.v5"
30+
import "gopkg.in/bluesuncorp/validator.v6"
3131

3232
Usage and documentation
3333
------
3434

35-
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v5 for detailed usage docs.
35+
Please see http://godoc.org/gopkg.in/bluesuncorp/validator.v6 for detailed usage docs.
3636

3737
##### Example:
3838
```go
@@ -41,7 +41,7 @@ package main
4141
import (
4242
"fmt"
4343

44-
"gopkg.in/bluesuncorp/validator.v5"
44+
"gopkg.in/bluesuncorp/validator.v6"
4545
)
4646

4747
// User contains user information
@@ -66,7 +66,12 @@ var validate *validator.Validate
6666

6767
func main() {
6868

69-
validate = validator.New("validate", validator.BakedInValidators)
69+
config := validator.Config{
70+
TagName: "validate",
71+
ValidationFuncs: validator.BakedInValidators,
72+
}
73+
74+
validate = validator.New(config)
7075

7176
address := &Address{
7277
Street: "Eavesdown Docks",
@@ -83,31 +88,14 @@ func main() {
8388
Addresses: []*Address{address},
8489
}
8590

86-
// returns nil or *StructErrors
91+
// returns nil or ValidationErrors ( map[string]*FieldError )
8792
errs := validate.Struct(user)
8893

8994
if errs != nil {
9095

91-
// err will be of type *FieldError
92-
err := errs.Errors["Age"]
93-
fmt.Println(err.Error()) // output: Field validation for "Age" failed on the "lte" tag
94-
fmt.Println(err.Field) // output: Age
95-
fmt.Println(err.Tag) // output: lte
96-
fmt.Println(err.Kind) // output: uint8
97-
fmt.Println(err.Type) // output: uint8
98-
fmt.Println(err.Param) // output: 130
99-
fmt.Println(err.Value) // output: 135
100-
101-
// or if you prefer you can use the Flatten function
102-
// NOTE: I find this usefull when using a more hard static approach of checking field errors.
103-
// The above, is best for passing to some generic code to say parse the errors. i.e. I pass errs
104-
// to a routine which loops through the errors, creates and translates the error message into the
105-
// users locale and returns a map of map[string]string // field and error which I then use
106-
// within the HTML rendering.
107-
108-
flat := errs.Flatten()
109-
fmt.Println(flat) // output: map[Age:Field validation for "Age" failed on the "lte" tag Addresses[0].Address.City:Field validation for "City" failed on the "required" tag]
110-
err = flat["Addresses[0].Address.City"]
96+
fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag
97+
// Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag
98+
err := errs["User.Addresses[0].City"]
11199
fmt.Println(err.Field) // output: City
112100
fmt.Println(err.Tag) // output: required
113101
fmt.Println(err.Kind) // output: string
@@ -126,14 +114,18 @@ func main() {
126114
Benchmarks
127115
------
128116
###### Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3
117+
NOTE: allocations for structs are up from v5, however ns/op for parallel operations are way down.
118+
It was a decicion not to cache struct info because although it reduced allocation to v5 levels, it
119+
hurt parallel performance too much.
129120
```go
130121
$ go test -cpu=4 -bench=. -benchmem=true
131122
PASS
132-
BenchmarkValidateField-4 3000000 429 ns/op 192 B/op 2 allocs/op
133-
BenchmarkValidateStructSimple-4 500000 2877 ns/op 657 B/op 10 allocs/op
134-
BenchmarkTemplateParallelSimple-4 500000 3097 ns/op 657 B/op 10 allocs/op
135-
BenchmarkValidateStructLarge-4 100000 15228 ns/op 4350 B/op 62 allocs/op
136-
BenchmarkTemplateParallelLarge-4 100000 14257 ns/op 4354 B/op 62 allocs/op
123+
BenchmarkField-4 5000000 314 ns/op 16 B/op 1 allocs/op
124+
BenchmarkFieldOrTag-4 500000 2425 ns/op 20 B/op 2 allocs/op
125+
BenchmarkStructSimple-4 500000 3117 ns/op 553 B/op 14 allocs/op
126+
BenchmarkStructSimpleParallel-4 1000000 1149 ns/op 553 B/op 14 allocs/op
127+
BenchmarkStructComplex-4 100000 19580 ns/op 3230 B/op 102 allocs/op
128+
BenchmarkStructComplexParallel-4 200000 6686 ns/op 3232 B/op 102 allocs/op
137129
```
138130

139131
How to Contribute

doc.go

Lines changed: 20 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,9 @@
11
/*
2-
Package validator implements value validations for structs and individual fields based on tags. It can also handle Cross Field and Cross Struct validation for nested structs.
2+
Package validator implements value validations for structs and individual fields based on tags.
3+
It can also handle Cross Field and Cross Struct validation for nested structs and has the ability
4+
to dive into arrays and maps of any type.
35
4-
Validate
5-
6-
validate := validator.New("validate", validator.BakedInValidators)
7-
8-
errs := validate.Struct(//your struct)
9-
valErr := validate.Field(field, "omitempty,min=1,max=10")
10-
11-
A simple example usage:
12-
13-
type UserDetail struct {
14-
Details string `validate:"-"`
15-
}
16-
17-
type User struct {
18-
Name string `validate:"required,max=60"`
19-
PreferedName string `validate:"omitempty,max=60"`
20-
Sub UserDetail
21-
}
22-
23-
user := &User {
24-
Name: "",
25-
}
26-
27-
// errs will contain a hierarchical list of errors
28-
// using the StructErrors struct
29-
// or nil if no errors exist
30-
errs := validate.Struct(user)
31-
32-
// in this case 1 error Name is required
33-
errs.Struct will be "User"
34-
errs.StructErrors will be empty <-- fields that were structs
35-
errs.Errors will have 1 error of type FieldError
36-
37-
NOTE: Anonymous Structs - they don't have names so expect the Struct name
38-
within StructErrors to be blank.
39-
40-
Error Handling
41-
42-
The error can be used like so
43-
44-
fieldErr, _ := errs["Name"]
45-
fieldErr.Field // "Name"
46-
fieldErr.ErrorTag // "required"
47-
48-
Both StructErrors and FieldError implement the Error interface but it's
49-
intended use is for development + debugging, not a production error message.
50-
51-
fieldErr.Error() // Field validation for "Name" failed on the "required" tag
52-
errs.Error()
53-
// Struct: User
54-
// Field validation for "Name" failed on the "required" tag
55-
56-
Why not a better error message? because this library intends for you to handle your own error messages
6+
Why not a better error message? because this library intends for you to handle your own error messages.
577
588
Why should I handle my own errors? Many reasons, for us building an internationalized application
599
I needed to know the field and what validation failed so that I could provide an error in the users specific language.
@@ -66,21 +16,12 @@ I needed to know the field and what validation failed so that I could provide an
6616
return "Translated string based on field"
6717
}
6818
69-
The hierarchical error structure is hard to work with sometimes.. Agreed Flatten function to the rescue!
70-
Flatten will return a map of FieldError's but the field name will be namespaced.
71-
72-
// if UserDetail Details field failed validation
73-
Field will be "Sub.Details"
74-
75-
// for Name
76-
Field will be "Name"
77-
7819
Custom Functions
7920
8021
Custom functions can be added
8122
82-
//Structure
83-
func customFunc(top interface{}, current interface{}, field interface{}, param string) bool {
23+
// Structure
24+
func customFunc(topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
8425
8526
if whatever {
8627
return false
@@ -89,15 +30,15 @@ Custom functions can be added
8930
return true
9031
}
9132
92-
validate.AddFunction("custom tag name", customFunc)
33+
validate.RegisterValidation("custom tag name", customFunc)
9334
// NOTES: using the same tag name as an existing function
9435
// will overwrite the existing one
9536
9637
Cross Field Validation
9738
9839
Cross Field Validation can be implemented, for example Start & End Date range validation
9940
100-
// NOTE: when calling validate.Struct(val) val will be the top level struct passed
41+
// NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed
10142
// into the function
10243
// when calling validate.FieldWithValue(val, field, tag) val will be
10344
// whatever you pass, struct, field...
@@ -106,18 +47,7 @@ Cross Field Validation can be implemented, for example Start & End Date range va
10647
// Because of the specific requirements and field names within each persons project that
10748
// uses this library it is likely that custom functions will need to be created for your
10849
// Cross Field Validation needs, however there are some build in Generic Cross Field validations,
109-
// see Baked In Validators and Tags below
110-
111-
func isDateRangeValid(val interface{}, field interface{}, param string) bool {
112-
113-
myStruct := val.(myStructType)
114-
115-
if myStruct.Start.After(field.(time.Time)) {
116-
return false
117-
}
118-
119-
return true
120-
}
50+
// see Baked In Validators eqfield, nefield, gtfield, gtefield, ltfield, ltefield and Tags below
12151
12252
Multiple Validators
12353
@@ -135,7 +65,7 @@ Bad Validator definitions are not handled by the library
13565
Field `validate:"min=10,max=0"`
13666
}
13767
138-
// this definition of min max will never validate
68+
// this definition of min max will never succeed
13969
14070
Baked In Validators and Tags
14171
@@ -148,6 +78,11 @@ included within the parameter i.e. excludesall=, you will need to use the UTF-8
14878
representation 0x2C, which is replaced in the code as a comma, so the above will
14979
become excludesall=0x2C
15080
81+
NOTE3: pipe is the default separator of or validation tags, if you wish to have a pipe
82+
included within the parameter i.e. excludesall=| you will need to use the UTF-8 hex
83+
representation 0x7C, which is replaced in the code as a pipe, so the above will
84+
become excludesall=0x7C
85+
15186
Here is a list of the current built in validators:
15287
15388
-
@@ -162,14 +97,14 @@ Here is a list of the current built in validators:
16297
16398
structonly
16499
When a field that is a nest struct in encountered and contains this flag
165-
any validation on the nested struct such as "required" will be run, but
166-
none of the nested struct fields will be validated. This is usefull if
167-
inside of you program you know the struct will be valid, but need to
168-
verify it has been assigned.
100+
any validation on the nested struct will be run, but none of the nested
101+
struct fields will be validated. This is usefull if inside of you program
102+
you know the struct will be valid, but need to verify it has been assigned.
103+
NOTE: only "required" and "omitempty" can be used on a struct itself.
169104
170105
omitempty
171106
Allows conditional validation, for example if a field is not set with
172-
a value (Determined by the required validator) then other validation
107+
a value (Determined by the "required" validator) then other validation
173108
such as min or max won't run, but if a value is set validation will run.
174109
(Usage: omitempty)
175110

examples/simple.go

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package main
33
import (
44
"fmt"
55

6-
"gopkg.in/bluesuncorp/validator.v5"
6+
"gopkg.in/bluesuncorp/validator.v6"
77
)
88

99
// User contains user information
@@ -28,7 +28,12 @@ var validate *validator.Validate
2828

2929
func main() {
3030

31-
validate = validator.New("validate", validator.BakedInValidators)
31+
config := validator.Config{
32+
TagName: "validate",
33+
ValidationFuncs: validator.BakedInValidators,
34+
}
35+
36+
validate = validator.New(config)
3237

3338
address := &Address{
3439
Street: "Eavesdown Docks",
@@ -45,31 +50,14 @@ func main() {
4550
Addresses: []*Address{address},
4651
}
4752

48-
// returns nil or *StructErrors
53+
// returns nil or ValidationErrors ( map[string]*FieldError )
4954
errs := validate.Struct(user)
5055

5156
if errs != nil {
5257

53-
// err will be of type *FieldError
54-
err := errs.Errors["Age"]
55-
fmt.Println(err.Error()) // output: Field validation for "Age" failed on the "lte" tag
56-
fmt.Println(err.Field) // output: Age
57-
fmt.Println(err.Tag) // output: lte
58-
fmt.Println(err.Kind) // output: uint8
59-
fmt.Println(err.Type) // output: uint8
60-
fmt.Println(err.Param) // output: 130
61-
fmt.Println(err.Value) // output: 135
62-
63-
// or if you prefer you can use the Flatten function
64-
// NOTE: I find this usefull when using a more hard static approach of checking field errors.
65-
// The above, is best for passing to some generic code to say parse the errors. i.e. I pass errs
66-
// to a routine which loops through the errors, creates and translates the error message into the
67-
// users locale and returns a map of map[string]string // field and error which I then use
68-
// within the HTML rendering.
69-
70-
flat := errs.Flatten()
71-
fmt.Println(flat) // output: map[Age:Field validation for "Age" failed on the "lte" tag Addresses[0].Address.City:Field validation for "City" failed on the "required" tag]
72-
err = flat["Addresses[0].Address.City"]
58+
fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag
59+
// Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag
60+
err := errs["User.Addresses[0].City"]
7361
fmt.Println(err.Field) // output: City
7462
fmt.Println(err.Tag) // output: required
7563
fmt.Println(err.Kind) // output: string

0 commit comments

Comments
 (0)