SoFunction
Updated on 2025-03-03

golang validator library parameter verification practical tips

Several practical techniques for verifying the validator library parameter parameters

An inevitable link in web development is to verify the request parameters. Usually, we will define a model (struct) corresponding to the request parameters in the code, and quickly parse the parameters in the request with the help of model binding, such as in the gin frameworkBindandShouldBindSeries of methods. This article takes the gin framework's request parameter verification as an example and introduces somevalidatorPractical tips for the library.

Use of gin framework/go-playground/validatorPerform parameter verification, currently /go-playground/validator/v10 is supported, we need to use it when defining the structure.bindingTag identification related verification rules can be viewedValidator documentationView all supported tags.

Basic examples

First, let’s look at the built-in use of gin frameworkvalidatorBasic examples of parameter verification.

package main
import (
	"net/http"
	"/gin-gonic/gin"
)
type SignUpParam struct {
	Age        uint8  `json:"age" binding:"gte=1,lte=130"`
	Name       string `json:"name" binding:"required"`
	Email      string `json:"email" binding:"required,email"`
	Password   string `json:"password" binding:"required"`
	RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func main() {
	r := ()
	("/signup", func(c *) {
		var u SignUpParam
		if err := (&u); err != nil {
			(, {
				"msg": (),
			})
			return
		}
		// Save business logic codes such as in-store...		(, "success")
	})
	_ = (":8999")
}

We use curl to send a POST request under test:

curl -H "Content-type: application/json" -X POST -d '{"name":"q1mi","age":18,"email":""}' http://127.0.0.1:8999/signup

Output result:

{"msg":"Key: '' Error:Field validation for 'Email' failed on the 'email' tag\nKey: '' Error:Field validation for 'Password' failed on the 'required' tag\nKey: '' Error:Field validation for 'RePassword' failed on the 'required' tag"}

From the final output, you can seevalidatorThe inspection has taken effect, but the field of the error prompt is not particularly friendly, we may need to translate it into Chinese.

Translation verification error message

validatorThe library itself supports internationalization, and the corresponding language package can realize automatic translation of verification error prompt information. The following sample code demonstrates how to translate error message into Chinese, and the method of translation into other languages ​​is similar.

package main
import (
	"fmt"
	"net/http"
	"/gin-gonic/gin"
	"/gin-gonic/gin/binding"
	"/go-playground/locales/en"
	"/go-playground/locales/zh"
	ut "/go-playground/universal-translator"
	"/go-playground/validator/v10"
	enTranslations "/go-playground/validator/v10/translations/en"
	zhTranslations "/go-playground/validator/v10/translations/zh"
)
// Define a global translator Tvar trans 
// InitTrans Initialize Translatorfunc InitTrans(locale string) (err error) {
	// Modify the Validator engine properties in the gin framework to achieve customization	if v, ok := ().(*); ok {
		zhT := () // Chinese translator		enT := () // English translator		// The first parameter is the fallback locale		// The following parameters are the locale that should be supported (supported multiple)		// uni := (zhT, zhT) is also OK		uni := (enT, zhT, enT)
		// locale usually depends on the 'Accept-Language' of the http request header		var ok bool
		// You can also use (...) to pass multiple locales for search		trans, ok = (locale)
		if !ok {
			return ("(%s) failed", locale)
		}
		// Register a translator		switch locale {
		case "en":
			err = (v, trans)
		case "zh":
			err = (v, trans)
		default:
			err = (v, trans)
		}
		return
	}
	return
}
type SignUpParam struct {
	Age        uint8  `json:"age" binding:"gte=1,lte=130"`
	Name       string `json:"name" binding:"required"`
	Email      string `json:"email" binding:"required,email"`
	Password   string `json:"password" binding:"required"`
	RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func main() {
	if err := InitTrans("zh"); err != nil {
		("init trans failed, err:%v\n", err)
		return
	}
	r := ()
	("/signup", func(c *) {
		var u SignUpParam
		if err := (&u); err != nil {
			// Get type errors			errs, ok := err.()
			if !ok {
				// Non-type errors are returned directly				(, {
					"msg": (),
				})
				return
			}
			// Translate the type error			(, {
				"msg":(trans),
			})
			return
		}
		// Save specific business logic codes such as in-store...		(, "success")
	})
	_ = (":8999")
}

The same request is again:

curl -H "Content-type: application/json" -X POST -d '{"name":"q1mi","age":18,"email":""}' http://127.0.0.1:8999/signup

The output result this time is as follows:

{"msg":{"":"EmailMust be a valid email","":"PasswordAs required fields","":"RePasswordAs required fields"}}

Customize the field name of the error message

The above error prompt looks OK, but it is still almost the same. First of all, the fields in the error prompt are not the fields used in the request, for example:RePasswordis the field name in the structure defined by our backend, and the request isre_passwordField. How to use a custom name in the error prompt for fields, e.g.jsonWhat about the value specified by the tag?

Just add a get as follows when initializing the translatorjsonJust customize tags.

// InitTrans Initialize Translatorfunc InitTrans(locale string) (err error) {
	// Modify the Validator engine properties in the gin framework to achieve customization	if v, ok := ().(*); ok {
		// Register a custom method to get json tag		(func(fld ) string {
			name := (("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})
		zhT := () // Chinese translator		enT := () // English translator		// The first parameter is the fallback locale		// The following parameters are the locale that should be supported (supported multiple)		// uni := (zhT, zhT) is also OK		uni := (enT, zhT, enT)
		// ...  ...
}

Try sending a request again and see the effect:

{"msg":{"":"emailMust be a valid email","":"passwordAs required fields","SignUpParam.re_password":"re_passwordAs required fields"}}

You can see that the error message is used in our structurejsonThe name of the tag is set.

But there is still a bit of a flaw, that is, the final error message is still the structure name defined by our backend.SignUpParam, this name does not need to be returned to the front end with an error prompt, and the front end does not need this value. We need to find a way to get rid of it.

Here, refer to the method provided by /go-playground/validator/issues/633#issuecomment-654382345 to define a custom method to remove the prefix of the structure name:

func removeTopStruct(fields map[string]string) map[string]string {
	res := map[string]string{}
	for field, err := range fields {
		res[field[(field, ".")+1:]] = err
	}
	return res
}

We use the above function in the code to translate theerrorsJust do some processing:

if err := (&u); err != nil {
	// Get type errors	errs, ok := err.()
	if !ok {
		// Non-type errors are returned directly		(, {
			"msg": (),
		})
		return
	}
	// Translate the type error	// Use the removeTopStruct function to remove the structure name identifier in the field name	(, {
		"msg": removeTopStruct((trans)),
	})
	return
}

Take a look at the final effect:

{"msg":{"email":"Email must be a valid mailbox","password":"password is required","re_password":"re_password is a required field"}}

This time it seems to meet our expected standards.

Custom structure verification method

The above verification is still a little problem, which is when it involves some complex verification rules, such asre_passwordThe field needs to be withpasswordFor verification rules such as equal values, our custom error prompt field name method cannot solve other field names in the error prompt information well.

curl -H "Content-type: application/json" -X POST -d '{"name":"q1mi","age":18,"email":"","password":"123","re_password":"321"}' http://127.0.0.1:8999/signup

The last error message output is as follows:

{"msg":{"email":"Email must be a valid mailbox","re_password":"re_password must be equal to Password"}}

Can seere_passwordThe prompt message in the field still appearsPasswordThis structure field name. This is a little regretful, after all, the method of customizing the field name cannot affect the value passed in as param.

At this time, if you want to pursue better prompt effects, change the Password field above to andjsonThe consistent name of the tag requires us to customize the method of structure verification.

For example, weSignUpParamCustomize a verification method as follows:

// SignUpParamStructLevelValidation Custom SignUpParam structure verification functionfunc SignUpParamStructLevelValidation(sl ) {
	su := ().Interface().(SignUpParam)
	if  !=  {
		// Output error message, the last parameter is the passed param		(, "re_password", "RePassword", "eqfield", "password")
	}
}

Then register the custom verification method in the function that initializes the verification device:

func InitTrans(locale string) (err error) {
	// Modify the Validator engine properties in the gin framework to achieve customization	if v, ok := ().(*); ok {
		// ...  ...
		// Register a custom verification method for SignUpParam		(SignUpParamStructLevelValidation, SignUpParam{})
		zhT := () // Chinese translator		enT := () // English translator		// ...  ...
}

Finally, I requested it again and see the effect:

{"msg":{"email":"Email must be a valid mailbox","re_password":"re_password must be equal to password"}}

This timere_passwordThe error message in the field is in line with our expectations.

Custom field verification method

In addition to the custom structure verification method mentioned above,validatorIt also supports custom verification methods for a field and usesRegisterValidation()Register into the verifier instance.

Next we will doSignUpParamAdd a custom verification methodcheckDateFields for parameter verificationDate

type SignUpParam struct {
	Age        uint8  `json:"age" binding:"gte=1,lte=130"`
	Name       string `json:"name" binding:"required"`
	Email      string `json:"email" binding:"required,email"`
	Password   string `json:"password" binding:"required"`
	RePassword string `json:"re_password" binding:"required,eqfield=Password"`
	// Fields Date that require the custom verification method checkDate to perform parameter verification	Date       string `json:"date" binding:"required,datetime=2006-01-02,checkDate"`
}

where datetime=2006-01-02 is a built-in tag used to verify whether the date class parameters meet the specified format requirements. If thedateIf the parameters do not meet the format of 2006-01-02, the following error will be prompted:

{"msg":{"date":"The format of date must be 2006-01-02"}}

In addition to the built-in format requirements provided by datetime=2006-01-02, assuming that we also require that the time of the field must be a future time (later than the current time), a special verification requirement for a certain field requires us to use a custom field verification method.

First, we need to add a custom tag after the field that needs to perform a custom verification. Here we usecheckDate, pay attention to using English semicolons to separate them.

// customFunc custom field level verification methodfunc customFunc(fl ) bool {
	date, err := ("2006-01-02", ().String())
	if err != nil {
		return false
	}
	if (()) {
		return false
	}
	return true
}

Once the fields and their custom verification methods are defined, they need to be linked and registered in our verification device instance.

//Register custom verification methods in the verification deviceif err := ("checkDate", customFunc); err != nil {
	return err
}

In this way, we can use the request parametersdateFields are executed for customcheckDateVerified. We send the following request to test it:

curl -H "Content-type: application/json" -X POST -d '{"name":"q1mi","age":18,"email":"123@","password":"123", "re_password": "123", "date":"2020-01-02"}' http://127.0.0.1:8999/signup

The response result obtained at this time is:

{"msg":{"date":"Key: '' Error:Field validation for 'date' failed on the 'checkDate' tag"}}

This... the error message of the custom field-level verification method is very "simple and crude", which is different from the Chinese prompt style above. You must find a way to get it done!

Custom translation method

We now need to provide a custom translation method for custom field verification methods, so as to achieve a customized display of the field error prompt information.

// registerTranslator adds translation function to custom fieldsfunc registerTranslator(tag string, msg string)  {
	return func(trans ) error {
		if err := (tag, msg, false); err != nil {
			return err
		}
		return nil
	}
}
// translate custom fields translation methodfunc translate(trans , fe ) string {
	msg, err := ((), ())
	if err != nil {
		panic(fe.(error).Error())
	}
	return msg
}

After defining the relevant translation method, weInitTransCalled in the functionRegisterTranslation()Method to register our custom translation method.

// InitTrans Initialize Translatorfunc InitTrans(locale string) (err error) {
	// ......
		// Register a translator		switch locale {
		case "en":
			err = (v, trans)
		case "zh":
			err = (v, trans)
		default:
			err = (v, trans)
		}
		if err != nil {
			return err
		}
		// Notice!  Because trans instances will be used here		// So this step of registration must be placed after the trans initialization		if err := (
			"checkDate",
			trans,
			registerTranslator("checkDate", "{0}Must be later than the current date"),
			translate,
		); err != nil {
			return err
		}
		return
	}
	return
}

In this way, try to send the request again and you will get the desired error message.

{"msg":{"date":"date must be later than the current date"}}

The above is the detailed content of the practical tips for validator library parameter verification. For more information about validator library parameter verification, please pay attention to my other related articles!