Getting Started #
In this article you are going to learn how to use the go-playground/validator package to validate data in your go application. validator uses struct tags to specify the validation constraints. This allows seamless integration to existing applications without the need of excess re-write of existing code.
Installing validator #
Create a new go project and using the go get
command install the validator package as follows.
go get github.com/go-playground/validator/v10
At the time of writing, the current version of validator is v10
do check the GitHub Page to latest releases.
An example #
Let's take the example of signing up a user, we want email, password and an optional name.
type SignUpPayload struct {
Email string
Password string
Name string
}
Following are the validation requirements we want for our fields.
- Email is required and should be in email format.
- Password is required, should be minimum 8 characters and should contain atleast once special character from the set of !@#?.
- Name is optional, but if provided should be minimum 4 characters long.
Updating the example, adding struct tags.
type SignUpPayload struct {
Email string `validate:"required,email"`
Password string `validate:"required,min=8,containsany=!@#?*"`
Name string `validate:"omitempty,min=4"`
}
A lot of these tags should be self explanatory, requried
means fields cannot be empty, email
checks for email format, min
checks of minimum length, containsany
checks for existence of atleast once specified character.
You should use omitempty
when a field is optional, but when any value to the field is provided the validators will kick in.
The struct is ready, let's use the validator to actually validate an instance of this struct.
func main() {
// creating a signup payload
payload := SignUpPayload{
Email: "[email protected]",
Password: "securepass#",
}
// get an instance of a validator
v := validator.New()
// call the `Struct` function passing in your payload
err := v.Struct(payload)
if err != nil {
fmt.Println(err)
}
}
The above payload conforms to the validation rules provided previously so err
will be nil
. Let's see an exampel that will fail.
func main() {
payload := SignUpPayload{
Email: "test@testcom", // 👈 invalid email
Password: "securepass", // 👈 missing required character
Name: "123", // 👈 min length is not 4
}
v := validator.New()
err := v.Struct(payload)
if err != nil {
fmt.Println(err)
}
}
Running this example will print the following in the console.
Key: 'SignUpPayload.Email' Error:Field validation for 'Email' failed on the 'email' tag
Key: 'SignUpPayload.Password' Error:Field validation for 'Password' failed on the 'containsany' tag
Key: 'SignUpPayload.Name' Error:Field validation for 'Name' failed on the 'min' tag
Error handling #
While checking if err
is not nil
is enough to know that validation failed, sometimes you may want to have more information from the error produced. The errors procuded by validator is of type validator.ValidationErrors
, so you can cast the err to this type and obtain more information. Let me show you how.
func main() {
payload := SignUpPayload{...}
v := validator.New()
err := v.Struct(payload)
if err == nil {
return
}
// doing due diligence by checking cast was successful
validationErr, ok := err.(validator.ValidationErrors)
if !ok {
fmt.Println(err)
return
}
for _, vErr := range validationErr {
fmt.Printf("'%s' has a value of '%v' which does not satisfy '%s'.\n", vErr.Field(), vErr.Value(), vErr.Tag())
}
}
validator.ValidationErrors
is actually a slice of validator.FieldError
, so you can loop over all the errors.
The output of the above program will be:
'Email' has a value of 'test@testcom' which does not satisfy 'email'.
'Password' has a value of 'securepass' which does not satisfy 'containsany'.
'Name' has a value of '123' which does not satisfy 'min'.
Validating variables #
Validator provides the ability to validate individual variables using Var
function. First argument is the value to validate and second are the validation tags (just like in struct validation).
func main() {
var password = "securepass"
v := validator.New()
// 👇
err := v.Var(password, "required,min=8,containsany=!@#?*")
if err != nil {
fmt.Println(err)
}
}
End #
Recommendation: A point to note when using validator in your application is to use the same instace of validator throughout the application i.e. v := validator.New()
, use the same v
across your application. The reason as specified in the soruce code of validator:
It caches information about your struct and validations, in essence only parsing your validation tags once per struct type. Using multiple instances neglects the benefit of caching.
Valdiator provides over 100 validation tags, checkout the documentation here.
Thank you for reading this article 🙏🏻 more content coming soon.