Gogo-Gadget Validator is a simple struct validator based on field tags with the following features:
- Struct validation by setting validator tags on fields
- Customizable nil pointer validation
- Custom validations can be easily registered
- Context forwarding to be able to add context based validation
- Logical Operators
&&
,||
and!
for tags - Conditional Expressions
if(...)then(...) elif(...)then(...) else(...)
for tags
Download the module with go get:
go get github.com/gogo-gadget/validator
Import the module by adding:
import "github.com/gogo-gadget/validator"
In order to use the validation simply create a new instance of a validator by calling NewValidator()
.
You can then pass any struct, pointer or interface with underlying structs to its Validate
function.
An error will be returned if the validation failed and nil otherwise.
Have a look at the example below:
package main
import (
"context"
"log"
"github.com/gogo-gadget/validator"
)
type testStruct struct {
name string `validator:"required && len(9)"`
}
func main() {
ts := &testStruct{
name: "top-level",
}
v := validator.NewValidator()
ctx := context.Background()
err := v.Validate(ctx, ts)
if err != nil {
log.Fatal(err)
return
}
log.Println("hurray, validation succeeded")
}
The validator tag syntax contains rules for logical operators and conditional expressions. This implies that certain combinations of characters should not be used in custom validation tag regular expressions to guarantee the correct behavior of the validation.
Custom validation tags:
- should not start with:
if(
,!
- should always include the same number of opening
(
and closing)
brackets. - should not include any whitespace.
Negate a validation by placing a !
in front of the validation
type testStruct struct {
name string `validator:"!email"`
}
Chain validations by the &&
or ||
logical operators
type testStruct struct {
name string `validator:"required && len(7)"`
}
Put a validation into brackets (...)
to define order of operations
type testStruct struct {
email string `validator:"len(28) && (non-nil || email)"`
}
Use conditional expressions by writing tags of the form if(...)then(...) elif(...)then(...) else(...)
type testStruct struct {
email string `validator:"if(email)then(len(28)) elif(required)then(len(10)) else(non-nil)"`
}
In order to register a custom validator you need an instance of a validator and a custom validator being registered to it.
In order to create a custom validator one can use the provided factory function cv.NewCustomValidator
.
The function takes an id, regular expression, validation function and a configuration as parameters.
- The id is mainly used for the registration of the custom validator.
- The regular expression is being used to identify if a field should be validated or not.
- The validation function will be run on a field if the regular expression matched a subtag and potentially return an error.
- The configuration allows e.g. to define if the validation should fail if the field is part of a nil pointer to a struct.
Have a look at the example below:
package main
import (
"context"
"regexp"
"github.com/gogo-gadget/validator"
"github.com/gogo-gadget/validator/pkg/cv"
)
func main() {
v := validator.NewValidator()
customValidator := exampleValidator()
v.RegisterCustomValidator(customValidator)
}
func exampleValidator() *cv.CustomValidator {
exampleString := "example"
exampleRegexp := regexp.MustCompile(exampleString)
customValidator := cv.NewCustomValidator("example", exampleRegexp, validateExampleValidator, cv.NewCustomValidatorConfig().FailForNilValue())
return customValidator
}
func validateExampleValidator(ctx context.Context, f *cv.Field, vCtx *cv.ValidationContext) error {
// Validation of the field is placed here
// ...
return nil
}
Since the id will be used for the registration it allows a regular expression for the field tag to be used multiple times. That does also imply that if one registers two custom validators with the same id, only the last registered will be used.
Feel free to contribute and e.g. add useful custom validators by opening pull requests.