![](/style/images/good.png)
![](/style/images/bad.png)
介绍一个golang struct 校验工具【qvalid】
source link: https://blog.csdn.net/oqqYuan1234567890/article/details/90342731
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
这个库是去年写的,主要用于结构体的校验。
比如字符串长度、数值大小、oneof,以及字符串的一些常见属性(email/url/ip)等。
项目的地址:https://github.com/miaomiao3/qvalid
因为不想用一些现成但很臃肿的库如govalidator,就自己写了一个,写的时候希望语法尽可能精简,借用了mongodb的一些约束,比如lt/lte gt/gte概念,来约束字符串的长度或者数值的值大小。由于开发的时候是针对某些特定场合用的,所以完备性是有待提高的(主要的代码大概花了半天那样子,就是说可能有bug哈,如果有兴趣可以提issue和pr)。但是基本功能是没问题的。
下面内容摘自repo的readme,懒得翻成中文了,将就看一下吧。
qvalid
powerful tool to validate struct’s exported fields
Features
- validate field value of numbers(int/uint/float…)
- validate field length of string/array/slice/map
- support in check
- when a field is slice and its element is struct/struct_pointer, qvalid auto validate this struct related element
- when a field is string, support attribute check. e.g. email/ip/email…
- pretty field output msg, use json tag first as field name
Install
go get -u github.com/miaomiao3/qvalid
Syntax
- As for bound limit, it means length of string/array/slice/map, and value of numbers(int/uint/float…)
- If ‘in’ was set, do not set bound limit
,
and=
reserved[
and]
reserved except ofin
constraint
constraint description
attr
is available as below
const (
StringTypeEmail = "email"
StringTypeAlpha = "alpha"
StringTypeUpperAlpha = "upper_alpha"
StringTypeLowerAlpha = "lower_alpha"
StringTypeAlphaNumeric = "alpha_numeric"
StringTypeNumeric = "numeric"
StringTypeInt = "int"
StringTypeFloat = "float"
StringTypeHex = "hex"
StringTypeAscii = "ascii"
StringTypeVisibleAscii = "visible_ascii"
StringTypeBytes = "bytes"
StringTypeBase64 = "base64"
StringTypeDNS = "dns"
StringTypeVersion = "version"
StringTypeIp = "ip"
StringTypePort = "port"
StringTypeURL = "url"
)
Examples
First, define some struct:
type Dog struct {
Name string `valid:"in=[rose,tulip]" json:"name"`
Color string `valid:"lt=5, gte=3" json:"color"`
Weight float64 `valid:"lt=100, gte=10" json:"weight"`
Clothes int `valid:"in=[1,3,5]" json:"clothes"`
NickNames []string `valid:"lt=5, gt=1"`
Relations map[string]string `valid:"lt=5, gt=1"`
Email string `valid:"attr=email"`
from string `json:"from" valid:"lt=10, gt=1"` // unexported, will be ignored by qvalid
}
type BadTag struct {
Err1 string `valid:"lt=10, lte=1"` // this will cause [qvalid] error msg
Err2 string `valid:"gt=10, gte=1"` // this will cause [qvalid] error msg
Err3 string `valid:"lt=10, gt=1, in=[aa,bb]"` // this will cause [qvalid] error msg
Err4 string `valid:"lt=1, gte=1"` // this will cause [qvalid] error msg
}
type FakeFood struct {
Leaf Leaf
MainLeaf *Leaf
}
type Food struct {
Leafs []Leaf `valid:"gte=1"`
}
type Leaf struct {
Name string `valid:"in=[rose,tulip]" json:"name"`
}
validate struct with simple field
like Dog
func validateSimpleField() {
dog := &Dog{}
isPass, validErrors := qvalid.ValidateStruct(dog)
fmt.Println("validateSimpleField")
checkAndDumpValidErrors(isPass, validErrors)
newFlower := &Dog{
Name: "rose",
Color: "gray",
Weight: 30.0,
Clothes: 3,
NickNames: []string{"wangcai", "dawang"},
Relations: map[string]string{
"owner": "cy",
"birth": "2018",
},
Email: "[email protected]",
}
isPass, validErrors = qvalid.ValidateStruct(newFlower)
checkAndDumpValidErrors(isPass, validErrors)
}
output:
validateSimpleField
illegal input and result:
isPass:false
validErrors:
err:0 --> &{Field:.name Msg:value: not in:[rose tulip]}
err:1 --> &{Field:.color Msg:expect length >= 3 but get length: 0}
err:2 --> &{Field:.weight Msg:expect value >= 10 but get value:0}
err:3 --> &{Field:.clothes Msg:value:0 not in:[1 3 5]}
err:4 --> &{Field:.NickNames Msg:expect length > 1 but get length: 0}
err:5 --> &{Field:.Relations Msg:expect length > 1 but get length: 0}
err:6 --> &{Field:.Email Msg:value: not match attribute:email}
legal input and result:
isPass:true
validate embedded struct
like FakeFood
func validateEmbedStruct() {
food := &FakeFood{
MainLeaf: &Leaf{},
}
isPass, validErrors := qvalid.ValidateStruct(food)
fmt.Println("validateEmbedStruct")
checkAndDumpValidErrors(isPass, validErrors)
newFakeFood := FakeFood{
Leaf: Leaf{
Name: "rose",
},
MainLeaf: &Leaf{
Name: "rose",
},
}
isPass, validErrors = qvalid.ValidateStruct(newFakeFood)
checkAndDumpValidErrors(isPass, validErrors)
}
output
validateEmbedStruct
illegal input and result:
isPass:false
validErrors:
err:0 --> &{Field:.Leaf.name Msg:value: not in:[rose tulip]}
err:1 --> &{Field:.MainLeaf.name Msg:value: not in:[rose tulip]}
legal input and result:
isPass:true
validate slice embedded struct
like Food
func validateSliceEmbedStruct() {
food := &Food{
Leafs: []Leaf{ // if Leafs is empty, qvalid do not check empty slice field, so set 1 element to test
Leaf{},
},
}
isPass, validErrors := qvalid.ValidateStruct(food)
fmt.Println("validateSliceEmbedStruct")
checkAndDumpValidErrors(isPass, validErrors)
newFood := Food{
Leafs: []Leaf{
Leaf{
Name: "rose",
},
},
}
isPass, validErrors = qvalid.ValidateStruct(newFood)
checkAndDumpValidErrors(isPass, validErrors)
}
output
validateSliceEmbedStruct
illegal input and result:
isPass:false
validErrors:
err:0 --> &{Field:.Leafs[0].name Msg:value: not in:[rose tulip]}
legal input and result:
isPass:true
sample of bad tag
like Person
func badTag() {
bad := &BadTag{}
isPass, validErrors := qvalid.ValidateStruct(bad)
fmt.Println("badTag")
checkAndDumpValidErrors(isPass, validErrors)
}
output
badTag
illegal input and result:
isPass:false
validErrors:
err:0 --> &{Field:[qvalid] GetConstraintFromTag Msg:lt and lte can't both set}
err:1 --> &{Field:[qvalid] GetConstraintFromTag Msg:gt and gt can't both set}
err:2 --> &{Field:[qvalid] GetConstraintFromTag Msg:bound limit and 'in' can't both set}
err:3 --> &{Field:[qvalid] GetConstraintFromTag Msg:upper and lower bound limit illegal}
for more details, see example dir.
TODO:
- check pointer loop
- customized field validator
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK