这个库是去年写的,主要用于结构体的校验。
比如字符串长度、数值大小、oneof,以及字符串的一些常见属性(email/url/ip)等。
项目的地址:https://github.com/miaomiao3/qvalid
因为不想用一些现成但很臃肿的库如govalidator,就自己写了一个,写的时候希望语法尽可能精简,借用了mongodb的一些约束,比如lt/lte gt/gte概念,来约束字符串的长度或者数值的值大小。由于开发的时候是针对某些特定场合用的,所以完备性是有待提高的(主要的代码大概花了半天那样子,就是说可能有bug哈,如果有兴趣可以提issue和pr)。但是基本功能是没问题的。
下面内容摘自repo的readme,懒得翻成中文了,将就看一下吧。
powerful tool to validate struct’s exported fields
go get -u github.com/miaomiao3/qvalid
,
and =
reserved[
and ]
reserved except of in
constraintconstraint | description | comment |
---|---|---|
lt | little than, upper bound limit | u can set lt or lte! |
lte | little than or equal, upper bound limit | u can set lt or lte! |
gt | greater than, lower bound limit | u can set gt or gte! |
gte | greater than or equal, lower bound limit | u can set gt or gte! |
in | must in one of the list item. item character must be numeric or alpha | If ‘in’ was set, do not set bound limit |
attr | when the field is string, it works to some known attribute like email, ip .etc | attr desc |
attr
is available as belowconst (
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"
)
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"`
}
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
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
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
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.