Introduction
Validator is an open source validator package that can quickly verify whether the input information conforms to custom rules. Currently, it has 7.8k stars on Github .
Installation
go get github.com/go-playground/validator
Import
import "github.com/go-playground/validator"
Example
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)
// Define an add user parameter structure
type AddUserPost struct {
Name string `json:"name" validate:"required"` //Required
Email string `json:"email" validate:"required,email"` // Required Fill in, and the format is email
Age uint8 `json:"age" validate:"gte=18,lte=30"` // age range
}
// Simple example
func main () {
engine := gin . Default ()
engine . POST ( "/valid" , func ( context * gin . Context ) {
var adduserPost AddUserPost
// Receive parameter
err := context . ShouldBindJSON ( & adduserPost )
if err != nil {
context . JSON ( 500 , gin . H { "msg" : err })
return
}
fmt . Printf ( "adduserPost: %+v \n " , adduserPost )
// Validate with Validate
validate := validator . New ()
err = validate . Struct ( adduserPost )
if err != nil {
fmt . Println ( err )
context . JSON ( 500 , gin . H { "msg" : err . Error ()})
return
}
context . JSON ( 200 , gin . H { "msg" : "success" })
})
_ = engine . Run ( ":9090" )
}
# When the email is invalid
$ curl -X POST http://127.0.0.1:9090/valid -d '{"name":"Marsero","email":"marsero","age":26}'
{ "msg" :"Key: 'AddUserPost.Email' Error:Field validation for 'Email' failed on the 'email' tag" } %
# When age is not in the specified range
$ curl -X POST http://127.0.0.1:9090/valid -d '{"name":"Marsero","email":"marsero@mars.com","age":17}'
{ "msg" :"Key: 'AddUserPost.Age' Error:Field validation for 'Age' failed on the 'gte' tag" } %
# When name is not filled in
$ curl -X POST http://127.0.0.1:9090/valid -d '{"name":"","email":"marsero@mars.com","age":20}'
{ "msg" :"Key: 'AddUserPost.Name' Error:Field validation for 'Name' failed on the 'required' tag" } %
Translate to French
Code
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/fr"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
frs "github.com/go-playground/validator/v10/translations/fr"
)
var (
validate = validator . New () // instantiate validator
french = fr . New () // get French translator
uni = ut . New ( french , french ) // set to French translator
trans , _ = uni . GetTranslator ( "fr" ) // Get translation dictionary
)
type User struct {
Name string `form:"name" validate:"required,min=3,max=5"`
Email string `form:"email" validate:"email"`
Age int8 `form:"age" validate:"gte=18,lte=20"`
}
func main () {
engine := gin . Default ()
engine . GET ( "/language" , func ( context * gin . Context ) {
var user User
err := context . ShouldBindQuery ( & user )
if err != nil {
context . JSON ( 500 , gin . H { "msg" : err })
return
}
// register translator
_ = frs . RegisterDefaultTranslations ( validate , trans )
// use validator to validate
err = validate . Struct ( user )
if err != nil {
if errors , ok := err . ( validator . ValidationErrors ); ok {
// Translate and return
context . JSON ( 500 , gin . H {
"before translation" : errors . Error (),
"after translation " : errors . Translate ( trans ),
})
return
}
}
context . JSON ( 200 , gin . H { "msg" : "success" })
})
_ = engine . Run ( ":9090" )
}
# do not pass parameters
$ curl -X GET http://127.0.0.1:9090/language
# it returns
{
"after translation " :{
"User.Age" :"Age doit être 18 ou plus" ,
"User.Email" :"Email doit être une adresse email valide" ,
"User.Name" :"Name est un champ obligatoire"
} ,
"before translation" :"Key: 'User.Name' Error:Field validation for 'Name' failed on the 'required' tag \n Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag \n Key: 'User.Age' Error:Field validation for 'Age' failed on the 'gte' tag"
}
Validation rules
Organize some common rules
Tag
Description
required
Required
unique
Guarantees uniqueness, different types are handled differently; For map, unique
constraints have no repeated value
values; For arrays and slices, there are no repeated element values<br/ >
min
The minimum value, different types have different meanings The number type represents the minimum value. String type represents the minimum number of characters
max
The maximum value, different types have different meanings The number type represents the maximum value. String type represents the maximum number of characters
gte
greater than or equal to parameter value
gt
greater than parameter value
lt
less than parameter value
lte
less than d equals parameter value
email
Use email
to restrict fields to be email
oneof
Must be one of the specified values, such as: oneof=male or female
, only male or female
For more rules, you can check the documentation: https://github.com/go-playground/validator
Custom Rules
Code
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// verify pre
type CustomParam struct {
Pre string `validate:"pre=go_"`
}
func main () {
// instantiate validator
validate = validator . New ()
// register custom
tag_ = validate . RegisterValidation ( "pre" , ValidatePre )
cusParam := CustomParam {
Pre : "php_" ,
}
err := validate . Struct ( cusParam )
fmt . Println ( err )
}
// custom validation rule
func ValidatePre ( fl validator . FieldLevel ) bool {
return fl . Field () . String () == "go_"
}
Key: 'CustomParam.Pre' Error:Field validation for 'Pre' failed on the 'pre' tag
Use in Gin
Code
package main
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
// define structure
type User struct {
Name string `form:"name" binding:"required,min=3,max=5" `
BirthDate time . Time `form:"date" binding:"required,birth" time_format:"2006-01-02"`
}
// Run the program
func main () {
engine := gin . Default ()
// Register custom validation tags: birth
if validate , ok := binding . Validator . Engine () . ( * validator . Validate ); ok {
validate . RegisterValidation ( " birth" , checkBirthDate )
}
// Receive request
engine . GET ( "/valid" , func ( context * gin . Context ) {
var user User
// integration validation
err := context . ShouldBindQuery ( & user )
if err != nil {
context . JSON ( http . StatusBadRequest , gin . H { " error" : err . Error ()})
return
}
context . JSON ( http . StatusOK , gin . H { "msg" : "success" })
})
_ = engine . Run ( ":9090" )
}
// check birthday
func checkBirthDate ( fl validator . FieldLevel ) bool {
t , ok := fl . Field () . Interface () . ( time . Time )
if ok {
// current time should be greater than birthday time
if time . Now () . After ( t ) {
return true
}
}
return false
}
# When the name is wrong
$ curl -X GET http://127.0.0.1:9090/valid?name= Marsero&date= 2020-01-01
{ "error" :"Key: 'User.Name' Error:Field validation for 'Name' failed on the 'min' tag" }
# When the custom birth format is wrong
$ curl -X GET http://127.0.0.1:9090/valid?name= Marsero is three&date= 2020
{ "error" :"parsing time \" 2020 \" as \" 2006-01-02 \" : cannot parse \"\" as \" - \" " }
# all correct
$ curl -X GET http://127.0.0.1:9090/valid?name= Zhang is three&date= 2020-10-10
{ "msg" :"success" }
Error display json tag
....
// Register a custom method to get json tag
validate . RegisterTagNameFunc ( func ( field reflect . StructField ) string {
splitN := strings . SplitN ( field . Tag . Get ( "json" ), "," , 2 )
fmt . Println ( splitN )
n := splitN [ 0 ]
if n == "-" {
return ""
}
return n
})
err := validate . Struct ( s )
if err != nil {
....
}
More available here .