validator

package module
Version: v0.0.0-...-ddae368 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2015 License: Apache-2.0 Imports: 7 Imported by: 0

README

Package validator

Package validator implements variable validations

Installation

Just use go get.

go get gopkg.in/validator.v2

And then just import the package into your own code.

import (
	"gopkg.in/validator.v2"
)

Usage

Please see http://godoc.org/gopkg.in/validator.v2 for detailed usage docs. A simple example would be.

type NewUserRequest struct {
	Username string `validate:"min=3,max=40,regexp=^[a-zA-Z]$"`
	Name string     `validate:"nonzero"`
	Age int         `validate:"min=21"`
	Password string `validate:"min=8"`
}

nur := NewUserRequest{Username: "something", Age: 20}
if valid, errs := validator.Validate(nur); !valid {
	// values not valid, deal with errors here
}

Builtin validators

Here is the list of validators buildin in the package.

len
	For numeric numbers, max will simply make sure that the
	value is equal to the parameter given. For strings, it
	checks that the string length is exactly that number of
	characters. For slices,	arrays, and maps, validates the
	number of items. (Usage: len=10)

max
	For numeric numbers, max will simply make sure that the
	value is lesser or equal to the parameter given. For strings,
	it checks that the string length is at most that number of
	characters. For slices,	arrays, and maps, validates the
	number of items. (Usage: max=10)

min
	For numeric numbers, min will simply make sure that the value
	is greater or equal to the parameter given. For strings, it
	checks that the string length is at least that number of
	characters. For slices, arrays, and maps, validates the
	number of items. (Usage: min=10)

nonzero
	This validates that the value is not zero. The appropriate
	zero value is given by the Go spec (e.g. for int it's 0, for
	string it's "", for pointers is nil, etc.) Usage: nonzero

regexp
	Only valid for string types, it will validator that the
	value matches the regular expression provided as parameter.
	(Usage: regexp=^a.*b$)

Custom validators

It is possible to define custom validators by using SetValidationFunc. First, one needs to create a validation function.

// Very simple validator
func notZZ(v interface{}, param string) error {
	st := reflect.ValueOf(v)
	if st.Kind() != reflect.String {
        return errors.New("notZZ only validates strings")
	}
	if st.String() == "ZZ" {
        return errors.New("value cannot be ZZ")
	}
	return nil
}

Then one needs to add it to the list of validators and give it a "tag" name.

validator.SetValidationFunc("notzz", notZZ)

Then it is possible to use the notzz validation tag. This will print "Field A error: value cannot be ZZ"

type T struct {
	A string  `validate:"nonzero,notzz"`
}
t := T{"ZZ"}
if valid, errs := validator.Validate(t); !valid {
	fmt.Printf("Field A error: %s\n", errs["A"][0])
}

You can also have multiple sets of validator rules with SetTag().

type T struct {
	A int `foo:"nonzero" bar:"min=10"`
}
t := T{5}
SetTag("foo")
validator.Validate(t) // valid as it's nonzero
SetTag("bar")
validator.Validate(t) // invalid as it's less than 10

SetTag is probably better used with multiple validators.

fooValidator := validator.NewValidator()
fooValidator.SetTag("foo")
barValidator := validator.NewValidator()
barValidator.SetTag("bar")
fooValidator.Validate(t)
barValidator.Validate(t)

This keeps the default validator's tag clean. Again, please refer to godocs for a lot of more examples and different uses.

Pull requests policy

tl;dr. Contributions are welcome.

The repository is organized in version branches. Pull requests to, say, the v2 branch that break API compatibility will not be accepted. It is okay to break the API in master, not in the branches.

As for validation functions, the preference is to keep the main code simple and add most new functions to the validator-contrib repository.

https://github.com/go-validator/validator-contrib

For improvements and/or fixes to the builtin validation functions, please make sure the behaviour will not break existing functionality in the branches. If you see a case where the functionality of the builtin will change significantly, please send a pull request against master. We can discuss then whether the changes should be incorporated in the version branches as well.

License

Copyright 2014 Roberto Teixeira robteix@robteix.com

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Overview

Package validator implements value validations based on struct tags.

In code it is often necessary to validate that a given value is valid before using it for something. A typical example might be something like this.

if age < 18 {
	return error.New("age cannot be under 18")
}

This is a simple enough example, but it can get significantly more complex, especially when dealing with structs.

l := len(strings.Trim(s.Username))
if l < 3 || l > 40  || !regexp.MatchString("^[a-zA-Z]$", s.Username) ||	s.Age < 18 || s.Password {
	return errors.New("Invalid request")
}

You get the idea. Package validator allows one to define valid values as struct tags when defining a new struct type.

type NewUserRequest struct {
	Username string `validate:"min=3,max=40,regexp=^[a-zA-Z]$"`
	Name string     `validate:"nonzero"`
	Age int         `validate:"min=18"`
	Password string `validate:"min=8"`
}

Then validating a variable of type NewUserRequest becomes trivial.

nur := NewUserRequest{Username: "something", ...}
if valid, _ := validator.Validate(nur); valid {
	// do something
}

Builtin validator functions

Here is the list of validator functions builtin in the package.

max
	For numeric numbers, max will simply make sure that the value is
	equal to the parameter given. For strings, it checks that
	the string length is exactly that number of characters. For slices,
	arrays, and maps, validates the number of items. (Usage: len=10)

max
	For numeric numbers, max will simply make sure that the value is
	lesser or equal to the parameter given. For strings, it checks that
	the string length is at most that number of characters. For slices,
	arrays, and maps, validates the number of items. (Usage: max=10)

min
	For numeric numbers, min will simply make sure that the value is
	greater or equal to the parameter given. For strings, it checks that
	the string length is at least that number of characters. For slices,
	arrays, and maps, validates the number of items. (Usage: min=10)

nonzero
	This validates that the value is not zero. The appropriate zero value
	is given by the Go spec (e.g. for int it's 0, for string it's "", for
	pointers is nil, etc.) Usage: nonzero

regexp
	Only valid for string types, it will validate that the value matches
	the regular expression provided as parameter. (Usage: regexp=^a.*b$)

Note that there are no tests to prevent conflicting validator parameters. For instance, these fields will never be valid.

...
A int     `validate:"max=0,min=1"`
B string  `validate:"len=10,regexp=^$"
...

Custom validation functions

It is possible to define custom validation functions by using SetValidationFunc. First, one needs to create a validation function.

// Very simple validation func
func notZZ(v interface{}, param string) error {
	st := reflect.ValueOf(v)
	if st.Kind() != reflect.String {
		return validate.ErrUnsupported
	}
	if st.String() == "ZZ" {
		return errors.New("value cannot be ZZ")
	}
	return nil
}

Then one needs to add it to the list of validation funcs and give it a "tag" name.

validate.SetValidationFunc("notzz", notZZ)

Then it is possible to use the notzz validation tag. This will print "Field A error: value cannot be ZZ"

type T struct {
	A string  `validate:"nonzero,notzz"`
}
t := T{"ZZ"}
if valid, errs := validator.Validate(t); !valid {
	fmt.Printf("Field A error: %s\n", errs["A"][0])
}

To use parameters, it is very similar.

// Very simple validator with parameter
func notSomething(v interface{}, param string) error {
	st := reflect.ValueOf(v)
	if st.Kind() != reflect.String {
		return validate.ErrUnsupported
	}
	if st.String() == param {
		return errors.New("value cannot be " + param)
	}
	return nil
}

And then the code below should print "Field A error: value cannot be ABC".

validator.SetValidationFunc("notsomething", notSomething)
type T struct {
	A string  `validate:"notsomething=ABC"`
}
t := T{"ABC"}
if valid, errs := validator.Validate(t); !valid {
	fmt.Printf("Field A error: %s\n", errs["A"][0])
}

As well, it is possible to overwrite builtin validation functions.

validate.SetValidationFunc("min", myMinFunc)

And you can delete a validation function by setting it to nil.

validate.SetValidationFunc("notzz", nil)
validate.SetValidationFunc("nonzero", nil)

Using a non-existing validation func in a field tag will always return false and with error validate.ErrUnknownTag.

Finally, package validator also provides a helper function that can be used to validate simple variables/values.

    // valid: true, errs: []
	valid, errs = validator.Valid(42, "min=10, max=50")

	// valid: false, errs: [validate.ErrZeroValue]
	valid, errs = validator.Valid(nil, "nonzero")

	// valid: false, errs: [validate.ErrMin,validate.ErrMax]
	valid, errs = validator.Valid("hi", "nonzero,min=3,max=2")

Custom tag name

In case there is a reason why one would not wish to use tag 'validate' (maybe due to a conflict with a different package), it is possible to tell the package to use a different tag.

validator.SetTag("valid")

Then.

Type T struct {
	A int    `valid:"min=8, max=10"`
	B string `valid:"nonzero"`
}

SetTag is permanent. The new tag name will be used until it is again changed with a new call to SetTag. A way to temporarily use a different tag exists.

validator.WithTag("foo").Validate(t)
validator.WithTag("bar").Validate(t)
// But this will go back to using 'validate'
validator.Validate(t)

Multiple validators

You may often need to have a different set of validation rules for different situations. In all the examples above, we only used the default validator but you could create a new one and set specific rules for it.

For instance, you might use the same struct to decode incoming JSON for a REST API but your needs will change when you're using it to, say, create a new instance in storage vs. when you need to change something.

type User struct {
	Username string `validate:"nonzero"`
	Name string     `validate:"nonzero"`
	Age int         `validate:"nonzero"`
	Password string `validate:"nonzero"`
}

Maybe when creating a new user, you need to make sure all values in the struct are filled, but then you use the same struct to handle incoming requests to, say, change the password, in which case you only need the Username and the Password and don't care for the others. You might use two different validators.

type User struct {
	Username string `creating:"nonzero" chgpw:"nonzero"`
	Name string     `creating:"nonzero"`
	Age int         `creating:"nonzero"`
	Password string `creating:"nonzero" chgpw:"nonzero"`
}

var (
	creationValidator = validator.NewValidator()
	chgPwValidator = validator.NewValidator()
)

func init() {
	creationValidator.SetTag("creating")
	chgPwValidator.SetTag("chgpw")
}

...

func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
	var u User
	json.NewDecoder(r.Body).Decode(&user)
	if valid, _ := creationValidator.Validate(user); !valid {
		// the request did not include all of the User
		// struct fields, so send a http.StatusBadRequest
		// back or something
	}
	// create the new user
}

func SetNewUserPasswordHandler(w http.ResponseWriter, r *http.Request) {
	var u User
	json.NewDecoder(r.Body).Decode(&user)
	if valid, _ := chgPwValidator.Validate(user); !valid {
		// the request did not Username and Password,
		// so send a http.StatusBadRequest
		// back or something
	}
	// save the new password
}

It is also possible to do all of that using only the default validator as long as SetTag is always called before calling validator.Validate() or you chain the with WithTag().

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrZeroValue is the error returned when variable has zero valud
	// and nonzero was specified
	ErrZeroValue = TextErr{errors.New("zero value")}
	// ErrMin is the error returned when variable is less than mininum
	// value specified
	ErrMin = TextErr{errors.New("less than min")}
	// ErrMax is the error returned when variable is more than
	// maximum specified
	ErrMax = TextErr{errors.New("greater than max")}
	// ErrLen is the error returned when length is not equal to
	// param specified
	ErrLen = TextErr{errors.New("invalid length")}
	// ErrRegexp is the error returned when the value does not
	// match the provided regular expression parameter
	ErrRegexp = TextErr{errors.New("regular expression mismatch")}
	// ErrUnsupported is the error error returned when a validation rule
	// is used with an unsupported variable type
	ErrUnsupported = TextErr{errors.New("unsupported type")}
	// ErrBadParameter is the error returned when an invalid parameter
	// is provided to a validation rule (e.g. a string where an int was
	// expected (max=foo,len=bar) or missing a parameter when one is required (len=))
	ErrBadParameter = TextErr{errors.New("bad parameter")}
	// ErrUnknownTag is the error returned when an unknown tag is found
	ErrUnknownTag = TextErr{errors.New("unknown tag")}
	// ErrInvalid is the error returned when variable is invalid
	// (normally a nil pointer)
	ErrInvalid = TextErr{errors.New("invalid value")}
)

Functions

func SetMultiValidationFunc

func SetMultiValidationFunc(name string, vf MultiValidationFunc) error

func SetTag

func SetTag(tag string)

SetTag allows you to change the tag name used in structs

Example

This example shows you how to change the tag name

package main

import (
	"fmt"

	"github.com/mash/validator"
)

func main() {
	type T struct {
		A int `foo:"nonzero" bar:"min=10"`
	}
	t := T{5}
	v := validator.NewValidator()
	v.SetTag("foo")
	err := v.Validate(t)
	fmt.Printf("foo --> valid: %v, errs: %v\n", err == nil, err)
	v.SetTag("bar")
	err = v.Validate(t)
	errs := err.(validator.ErrorMap)
	fmt.Printf("bar --> valid: %v, errs: %v\n", err == nil, errs)

}
Output:

foo --> valid: true, errs: <nil>
bar --> valid: false, errs: A: less than min

func SetValidationFunc

func SetValidationFunc(name string, vf ValidationFunc) error

SetValidationFunc sets the function to be used for a given validation constraint. Calling this function with nil vf is the same as removing the constraint function from the list.

func Valid

func Valid(val interface{}, tags string) error

Valid validates a value based on the provided tags and returns errors found or nil.

Example

This example shows how to use the Valid helper function to validator any number of values

package main

import (
	"fmt"

	"github.com/mash/validator"
)

func main() {
	err := validator.Valid(42, "min=10,max=100,nonzero")
	fmt.Printf("42: valid=%v, errs=%v\n", err == nil, err)

	var ptr *int
	if err := validator.Valid(ptr, "nonzero"); err != nil {
		fmt.Println("ptr: Invalid nil pointer.")
	}

	err = validator.Valid("ABBA", "regexp=[ABC]*")
	fmt.Printf("ABBA: valid=%v\n", err == nil)

}
Output:

42: valid=true, errs=<nil>
ptr: Invalid nil pointer.
ABBA: valid=true

func Validate

func Validate(v interface{}) error

Validate validates the fields of a struct based on 'validator' tags and returns errors found indexed by the field name.

Example

This example demonstrates a custom function to process template text. It installs the strings.Title function and uses it to Make Title Text Look Good In Our Template's Output.

package main

import (
	"fmt"
	"sort"

	"github.com/mash/validator"
)

func main() {
	// First create a struct to be validated
	// according to the validator tags.
	type ValidateExample struct {
		Name        string `validate:"nonzero"`
		Description string
		Age         int    `validate:"min=18"`
		Email       string `validate:"regexp=^[0-9a-z]+@[0-9a-z]+(\\.[0-9a-z]+)+$"`
		Address     struct {
			Street string `validate:"nonzero"`
			City   string `validate:"nonzero"`
		}
	}

	// Fill in some values
	ve := ValidateExample{
		Name:        "Joe Doe", // valid as it's nonzero
		Description: "",        // valid no validation tag exists
		Age:         17,        // invalid as age is less than required 18
	}
	// invalid as Email won't match the regular expression
	ve.Email = "@not.a.valid.email"
	ve.Address.City = "Some City" // valid
	ve.Address.Street = ""        // invalid

	err := validator.Validate(ve)
	if err == nil {
		fmt.Println("Values are valid.")
	} else {
		errs := err.(validator.ErrorMap)
		// See if Address was empty
		if errs["Address.Street"][0] == validator.ErrZeroValue {
			fmt.Println("Street cannot be empty.")
		}

		// Iterate through the list of fields and respective errors
		fmt.Println("Invalid due to fields:")

		// Here we have to sort the arrays to ensure map ordering does not
		// fail our example, typically it's ok to just range through the err
		// list when order is not important.
		var errOuts []string
		for f, e := range errs {
			errOuts = append(errOuts, fmt.Sprintf("\t - %s (%v)\n", f, e))
		}

		// Again this part is extraneous and you should not need this in real
		// code.
		sort.Strings(errOuts)
		for _, str := range errOuts {
			fmt.Print(str)
		}
	}

}
Output:

Street cannot be empty.
Invalid due to fields:
	 - Address.Street (zero value)
	 - Age (less than min)
	 - Email (regular expression mismatch)

Types

type ErrorArray

type ErrorArray []error

ErrorArray is a slice of errors returned by the Validate function.

func (ErrorArray) Error

func (err ErrorArray) Error() string

ErrorArray implements the Error interface and returns the first error as string if existent.

type ErrorMap

type ErrorMap map[string]ErrorArray

ErrorMap is a map which contains all errors from validating a struct.

func (ErrorMap) Error

func (err ErrorMap) Error() string

ErrorMap implements the Error interface so we can check error against nil. The returned error is if existent the first error which was added to the map.

type MultiValidationFunc

type MultiValidationFunc func(v interface{}, param string) error

type TextErr

type TextErr struct {
	Err error
}

TextErr is an error that also implements the TextMarshaller interface for serializing out to various plain text encodings. Packages creating their own custom errors should use TextErr if they're intending to use serializing formats like json, msgpack etc.

func (TextErr) Error

func (t TextErr) Error() string

Error implements the error interface.

func (TextErr) MarshalText

func (t TextErr) MarshalText() ([]byte, error)

MarshalText implements the TextMarshaller

type ValidationFunc

type ValidationFunc func(v interface{}, param string) error

ValidationFunc is a function that receives the value of a field and a parameter used for the respective validation tag.

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

Validator implements a validator

func NewValidator

func NewValidator() *Validator

NewValidator creates a new Validator

func WithTag

func WithTag(tag string) *Validator

WithTag creates a new Validator with the new tag name. It is useful to chain-call with Validate so we don't change the tag name permanently: validator.WithTag("foo").Validate(t)

Example

This example shows you how to change the tag name

package main

import (
	"fmt"

	"github.com/mash/validator"
)

func main() {
	type T struct {
		A int `foo:"nonzero" bar:"min=10"`
	}
	t := T{5}
	err := validator.WithTag("foo").Validate(t)
	fmt.Printf("foo --> valid: %v, errs: %v\n", err == nil, err)
	err = validator.WithTag("bar").Validate(t)
	fmt.Printf("bar --> valid: %v, errs: %v\n", err == nil, err)

}
Output:

foo --> valid: true, errs: <nil>
bar --> valid: false, errs: A: less than min

func (*Validator) SetMultiValidationFunc

func (mv *Validator) SetMultiValidationFunc(name string, vf MultiValidationFunc) error

func (*Validator) SetTag

func (mv *Validator) SetTag(tag string)

SetTag allows you to change the tag name used in structs

func (*Validator) SetValidationFunc

func (mv *Validator) SetValidationFunc(name string, vf ValidationFunc) error

SetValidationFunc sets the function to be used for a given validation constraint. Calling this function with nil vf is the same as removing the constraint function from the list.

func (*Validator) Valid

func (mv *Validator) Valid(val interface{}, tags string) error

Valid validates a value based on the provided tags and returns errors found or nil.

func (*Validator) Validate

func (mv *Validator) Validate(v interface{}) error

Validate validates the fields of a struct based on 'validator' tags and returns errors found indexed by the field name.

func (*Validator) WithTag

func (mv *Validator) WithTag(tag string) *Validator

WithTag creates a new Validator with the new tag name. It is useful to chain-call with Validate so we don't change the tag name permanently: validator.WithTag("foo").Validate(t)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL