[Go] parameter verification, object array verification-validator

background

In the go project I have been working on, I want to verify the interface parameter fields conveniently and concisely. I choose the validator library adapted to the gin framework as the verification component. The range check of the map type is relatively simple and easy to understand and easy to use. However, I suddenly encountered an unexpected error recently. The object array that was supposed to be checked did not check the field of each object in the array as I expected. Record whether the value meets the requirements.

Features

Range Comparison Validation

Range validation: slices, arrays and maps, strings, verify their length; values, verify size ranges

  • lte: less than or equal to the parameter value, validate: "lte=3" (less than or equal to 3)
  • gte: greater than or equal to the parameter value, validate: "lte=120,gte=0" (greater than or equal to 0 and less than or equal to 120)
  • lt: less than the parameter value, validate: "lt=3" (less than 3)
  • gt: greater than the parameter value, validate: "lt=120,gt=0" (greater than 0 and less than 120)
  • len: equal to the parameter value, validate: "len=2", the length of the string must be n, or the value of len in an array, slice, or map
  • max: maximum value, less than or equal to the parameter value, validate: "max=20" (less than or equal to 20)
  • min: Minimum value, greater than or equal to the parameter value, validate: "min=2,max=20" (greater than or equal to 2 and less than or equal to 20)
  • ne: not equal to, validate: "ne=2" (not equal to 2)
  • oneof: It can only be one of the listed values. These values ​​must be numbers or strings, separated by spaces. If there are spaces in the string, surround the string with single quotes. validate: "oneof=red green"

Explanation of special symbols between marks

  • Comma ( ,): Separate multiple verification tags. Note: There can be no spaces between the commas, validate: "lt=0,gt=100", there can be no spaces between the commas, otherwise panic
  • Horizontal line ( - ): skip this field without validation
  • vertical bar ( | ): use multiple validation tokens, but only one of them needs to be satisfied
  • required: Indicates that the field value must be set, and cannot be the default value
  • omitempty: If the field is not set, it is ignored

string validation

  • contains: contains the parameter substring, validate: "contains=tom" (the string value of the field contains tom)
  • excludes: contains the parameter substring, validate: "excludes=tom" (the string value of the field does not contain tom)
  • startswith: prefixed with the parameter substring, validate: "startswith=golang"
  • endswith: suffix with the parameter substring, validate: "startswith=world"

special string validation

  • email: The authentication string is in email format. Required by default
  • url: The authentication string is in URL format. Required by default
  • uri: Whether the field value contains a valid uri, validate: "uri"
  • ip: Whether the field value contains a valid IP address, validate: "ip"
  • ipv4: Whether the field value contains a valid ipv4 address, validate: "ipv4"
  • ipv6: Whether the field value contains a valid ipv6 address, validate: "ipv6"

example

Simple example, you can test it yourself

type UserInfo struct {
	ID   int    `validate:"gt=0"`
	Age  int    `validate:"gt=0"`
	Name string `validate:"required"`
	Sex  string `validate:"required"`
}
func InitUserInfo(id, age int, name, sex string) *UserInfo {
	// new一个校验器
	valid := validator.New()
	// 初始化UserInfo
	userInfo := &UserInfo{
		ID:   id,
		Age:  age,
		Name: name,
		Sex:  sex,
	}
	if err := valid.Struct(userInfo); err != nil {
		fmt.Println("参数校验不通过", err)
	}
	return userInfo
}
func TestValidate(t *testing.T) {
	InitUserInfo(1, 2, "kevin", "男") // 参数校验通过
	InitUserInfo(0, 2, "kevin", "男") // 参数校验不通过 Key: 'UserInfo.ID' Error:Field validation for 'ID' failed on the 'gt' tag
	InitUserInfo(1, 2, "kevin", "")  // 参数校验不通过 Key: 'UserInfo.Sex' Error:Field validation for 'Sex' failed on the 'required' tag
}

extended question

my question

verify slice

Because the structure of the project's interface parameters is complex, often nested with object arrays or slices, it is not simply a structure that can be generalized and received. Later in the project, a certain parameter in the object array that should be inspected is suddenly found, so The other party also neglected not to pass the value, which led to problems in the subsequent inspection. Although the problem was not on my side before the investigation, the verification field did not take effect. After the inspection, the inspection of the array, slice, or Map type needs to use dive. Validate into the next level of field.

example

sliceone := []string{
    
    "123", "onetwothree", "myslicetest", "four", "five"} 
validate.Var(sliceone, "max=15,dive,min=4")

output

Key: '[0]' Error:Field validation for '[0]' failed on the 'min' tag
Key: '' Error:Field validation for '' failed on the 'min' tag

illustrate

第二个参数中tag关键字 dive 前面的 max=15,验证 [] , 也就是验证slice的长度,
dive 后面的 min=4,验证slice里的值长度,也就是说 dive 后面的 tag 验证 slice 的值

Detailed example

Combined with the simple use example above, use dive to verify the implementation of sliced ​​array object fields


import (
	"fmt"
	"github.com/go-playground/validator/v10"
	"testing"
)

type UserInfo struct {
    
    
	ID   int    `validate:"gt=0"`
	Age  int    `validate:"gt=0"`
	Name string `validate:"required"`
	Sex  string `validate:"required"`
}

type Teacher struct {
    
    
	Member []*UserInfo `validate:"max=15,dive,required"`
}

func InitUserInfo(id, age int, name, sex string) *UserInfo {
    
    
	// new一个校验器
	valid := validator.New()
	// 初始化UserInfo
	userInfo := &UserInfo{
    
    
		ID:   id,
		Age:  age,
		Name: name,
		Sex:  sex,
	}
	var menber []*UserInfo
	menber = append(menber, userInfo)
	teacher := &Teacher{
    
    
		Member: menber,
	}
	if err := valid.Struct(teacher); err != nil {
    
    
		fmt.Println("参数校验不通过", err)
	}
	return userInfo
}

func TestValidate(t *testing.T) {
    
    
	InitUserInfo(1, 2, "kevin", "男") // 参数校验通过
	InitUserInfo(0, 2, "kevin", "男") // 参数校验不通过 Key: 'UserInfo.ID' Error:Field validation for 'ID' failed on the 'gt' tag
	InitUserInfo(1, 2, "kevin", "")  // 参数校验不通过 Key: 'UserInfo.Sex' Error:Field validation for 'Sex' failed on the 'required' tag
}

When the parameter in the teacher structure contains the user information structure, it needs to be added when the field of the user information needs to be verified validate:"max=15,dive,required", so that it is very easy to verify whether the field of the user information structure also meets the requirements.
The output is as follows . You can also use it
insert image description here
directly without adding the previous lengthvalidate:"dive,required"

two-dimensional slice

Of course, two-dimensional slices are similar in principle.

Example:

slicethree := [][]string{} validate.Var(slicethree, "min=2,dive,len=2,dive,required") 
validate.Var(slicethree, "min=2,dive,dive,required")

illustrate

这里有2个 dive,刚好深入到二维slice,但他们也有不同之处,第二个表达式的第一个dive后没有设置tag。
第一个验证表达式:
min=2:验证第一个 [] 方括号的值长度 ;
len=2:验证第二个 []string 长度;
required:验证slice里的值
第二个验证表达式:
min=2:验证第一个 [] 方括号的值长度 ;
dive: 后没有设置tag值,不验证第二个 []string ;
required: 验证slice里的值

map verification

The tag keyword dive is also required in the verification of the map. In addition, it also has two tags, keys and endkeys, to verify the key of the map between these two tags, not the value.

example

var mapone map[string]string mapone = map[string]string{"one": "jimmmy", "two": "tom", "three": ""}
 validate := validator.New() 
 err := validate.Var(mapone, "gte=3,dive,keys,eq=1|eq=2,endkeys,required")

output

Key: '[three]' Error:Field validation for '[three]' failed on the 'eq=1|eq=3' tag
Key: '[three]' Error:Field validation for '[three]' failed on the 'required' tag
Key: '[one]' Error:Field validation for '[one]' failed on the 'eq=1|eq=3' tag
Key: '[two]' Error:Field validation for '[two]' failed on the 'eq=1|eq=3' tag

illustrate

gte=3:验证map自己的长度;
dive后的 keys,eq=1|eq=2,endkeys:验证map的keys个数,也就是验证 [] 里值。上例中定义了一个string,所以明显报了3个错误。
required:验证 map的值value

Nested map verification

Such as: map[[3]string]string, similar to the above slice, using multiple dives

example

var maptwo map[[3]string]string{} validate.Var(maptwo, "gte=3,dive,keys,dive,eq=1|eq=3,endkeys,required")

illustrate

gte=3: 验证map的长度;
keys,dive,eq=1|eq=3,endkeys:keys和endkeys中有一个dive(深入一级),验证map中key的数组每一个值
required: 验证map的值

reference

Golang common library: field parameter validation library - validator uses
validator code address

Supongo que te gusta

Origin blog.csdn.net/ic_xcc/article/details/128387570
Recomendado
Clasificación