英文:
Golang: Validate Struct field of type string to be one of specific values
问题
golang版本:1.18.3
验证器:github.com/go-playground/validator/v10
我想在加载到嵌套结构数据结构后验证传入的JSON有效负载。这是我的传入JSON有效负载:
{
"name": "Duro",
"gender": "MALE",
"tier": 3,
"mobileNumber": "0356874586",
"address": {
"city": "Tokyo",
"street": "Shibaura St"
},
"children":[
{
"title": "Mr",
"lastName": "Takayashi"
}
],
"isEmployed": false,
"requestedAt": "2022-01-10T03:30:12.639Z"
}
这是我的user.go文件:
package main
type User struct {
Name string `validate:"required"`
Gender string `validate:"required,oneof=MALE FEMALE"`
Tier *uint8 `validate:"required,eq=0|eq=1|eq=2|eq=3"`
MobileNumber string `validate:"required"`
Email string
Address *Address `validate:"required"`
Children []Child `validate:"required,dive"`
IsEmployed *bool `validate:"required"`
PreferredContactMethod string `validate:"oneof=EMAIL PHONE POST SMS"`
RequestedAt time.Time `validate:"required"`
}
type Address struct {
City string `validate:"required"`
Street string `validate:"required"`
}
type Child struct {
Title string `validate:"required"`
FirstName string
LastName string `validate:"required"`
}
这是我的测试函数:
func TestUserPayload(t *testing.T) {
validate := validator.New()
var u User
err := json.Unmarshal([]byte(jsonData), &u)
if err != nil {
panic(err)
}
err := validate.Struct(&u)
if err != nil {
t.Errorf("error %v", err)
}
}
这个测试失败并显示错误:
error Key: 'User.PreferredContactMethod' Error:Field validation for 'PreferredContactMethod' failed on the 'oneof' tag
这是因为Go将空字符串赋给User.PreferredContactMethod结构字段。由于PreferredContactMethod
不是必需字段,当JSON有效负载中没有它时,我不想看到这个验证错误。我该如何避免在JSON有效负载中没有preferredContactMethod
字段时出现此错误消息?
如果您有更好的方法来实现此验证,也很乐意听取。
英文:
golang version: 1.18.3
validator: github.com/go-playground/validator/v10
I want to validate an incoming JSON payload after loaded into nested struct data structure. Here's my incoming JSON payload,
{
"name": "Duro",
"gender": "MALE",
"tier": 3,
"mobileNumber": "0356874586",
"address": {
"city": "Tokyo",
"street": "Shibaura St"
},
"children":[
{
"title": "Mr",
"lastName": "Takayashi"
}
],
"isEmployed": false,
"requestedAt": "2022-01-10T03:30:12.639Z"
}
Here's my user.go file,
package main
type User struct {
Name string `validate:"required"`
Gender string `validate:"required,oneof=MALE FEMALE"`
Tier *uint8 `validate:"required,eq=0|eq=1|eq=2|eq=3"`
MobileNumber string `validate:"required"`
Email string
Address *Address `validate:"required"`
Children []Child `validate:"required,dive"`
IsEmployed *bool `validate:"required"`
PreferredContactMethod string `validate:"oneof=EMAIL PHONE POST SMS"`
RequestedAt time.Time `validate:"required"`
}
type Address struct {
City string `validate:"required"`
Street string `validate:"required"`
}
type Child struct {
Title string `validate:"required"`
FirstName string
LastName string `validate:"required"`
}
Here's my test function
func TestUserPayload(t *testing.T) {
validate := validator.New()
var u User
err := json.Unmarshal([]byte(jsonData), &u)
if err != nil {
panic(err)
}
err := validate.Struct(&u)
if err != nil {
t.Errorf("error %v", err)
}
}
This test fails with error,
error Key: 'User.PreferredContactMethod' Error:Field validation for 'PreferredContactMethod' failed on the 'oneof' tag
This happens because Go assigns empty string to User.PreferredContactMethod struct field. Since PreferredContactMethod
is NOT a required field, I DON'T want to see this validation error when json payload doesn't have it.
How can I avoid this error message when the json payload doesn't have preferredContactMethod
field?
If you have better alternatives to achieve this validation, happy to hear them as well.
Here's the code in Go Playground
答案1
得分: 6
使用omitempty
和oneof
结合起来,使验证器库忽略空值或未设置的值。
type User struct {
Name string `validate:"required"`
Gender string `validate:"required,oneof=MALE FEMALE"`
Tier *uint8 `validate:"required,eq=0|eq=1|eq=2|eq=3"`
MobileNumber string `validate:"required"`
Email string
Address *Address `validate:"required"`
Children []Child `validate:"required,dive"`
IsEmployed *bool `validate:"required"`
PreferredContactMethod string `validate:"omitempty,oneof=EMAIL PHONE POST SMS"`
RequestedAt time.Time `validate:"required"`
}
英文:
Utilize omitempty
along with oneof
to make the validator library ignore empty or unset values.
type User struct {
Name string `validate:"required"`
Gender string `validate:"required,oneof=MALE FEMALE"`
Tier *uint8 `validate:"required,eq=0|eq=1|eq=2|eq=3"`
MobileNumber string `validate:"required"`
Email string
Address *Address `validate:"required"`
Children []Child `validate:"required,dive"`
IsEmployed *bool `validate:"required"`
PreferredContactMethod string `validate:"omitempty,oneof=EMAIL PHONE POST SMS"`
RequestedAt time.Time `validate:"required"`
}
答案2
得分: 1
使用https://github.com/marrow16/valix(https://pkg.go.dev/github.com/marrow16/valix)可以通过以下方式实现:
package main
import (
"fmt"
"time"
"github.com/marrow16/valix"
)
type User struct {
Name string `json:"name" v8n:"required, notNull"`
Gender string `json:"gender" v8n:"required, notNull, &strtoken{'MALE','FEMALE'}"`
Tier uint8 `json:"tier" v8n:"required, notNull, &mini{0}, &maxi{3}"`
DateOfBirth string `json:"dateOfBirth" v8n:"notNull, &strisod"`
MobileNumber string `json:"mobileNumber" v8n:"required, notNull, &strpatt{'^([0-9]{8,16})$'}"`
Email string `json:"email" v8n:"notNull"`
Address Address `json:"address" v8n:"required, notNull"`
Children []Child `json:"children" v8n:"required, notNull"`
IsEmployed bool `json:"isEmployed" v8n:"required"`
PreferredContactMethod string `json:"preferredContactMethod" v8n:"notNull, &strtoken{'EMAIL','PHONE','POST','SMS'}"`
RequestedAt time.Time `json:"requestedAt" v8n:"required, notNull, &strisodt"`
}
type Address struct {
City string `json:"city" v8n:"required, notNull"`
Street string `json:"street" v8n:"required, notNull"`
}
type Child struct {
Title string `json:"title" v8n:"required, notNull"`
FirstName string `json:"firstName" v8n:"notNull"`
LastName string `json:"lastName" v8n:"required, notNull"`
}
const jsonData = `{
"name": "Duro",
"gender": "MALE",
"tier": 3,
"dateOfBirth": "2000-01-13",
"mobileNumber": "0356874586",
"address": {
"city": "Tokyo",
"street": "Shibaura St"
},
"children":[
{
"title": "Mr",
"lastName": "Takayashi"
}
],
"isEmployed": false,
"requestedAt": "2022-01-10T03:30:12.639Z"
}`
var UserRequestValidator = valix.MustCompileValidatorFor(User{}, nil)
func main() {
user := User{}
ok, violations, _ := UserRequestValidator.ValidateStringInto(jsonData, &user)
if ok {
fmt.Println("Validation successful")
} else {
fmt.Println(fmt.Sprintf("Validation failed! (violations: %d)", len(violations)))
for _, v := range violations {
fmt.Printf("%s (property: '%s', path: '%s')\n", v.Message, v.Property, v.Path)
}
}
}
Go playground链接:https://go.dev/play/p/3zrkZx97m-e
声明:我是Valix的作者。
英文:
Using https://github.com/marrow16/valix (https://pkg.go.dev/github.com/marrow16/valix) it could be achieved with the following:
package main
import (
"fmt"
"time"
"github.com/marrow16/valix"
)
type User struct {
Name string `json:"name" v8n:"required, notNull"`
Gender string `json:"gender" v8n:"required, notNull, &strtoken{['MALE','FEMALE']}"`
Tier uint8 `json:"tier" v8n:"required, notNull, &mini{0}, &maxi{3}"`
DateOfBirth string `json:"dateOfBirth" v8n:"notNull, &strisod"`
MobileNumber string `json:"mobileNumber" v8n:"required, notNull, &strpatt{'^([0-9]{8,16})$'}"`
Email string `json:"email" v8n:"notNull"`
Address Address `json:"address" v8n:"required, notNull"`
Children []Child `json:"children" v8n:"required, notNull"`
IsEmployed bool `json:"isEmployed" v8n:"required"`
PreferredContactMethod string `json:"preferredContactMethod" v8n:"notNull, &strtoken{['EMAIL','PHONE','POST','SMS']}"`
RequestedAt time.Time `json:"requestedAt" v8n:"required, notNull, &strisodt"`
}
type Address struct {
City string `json:"city" v8n:"required, notNull"`
Street string `json:"street" v8n:"required, notNull"`
}
type Child struct {
Title string `json:"title" v8n:"required, notNull"`
FirstName string `json:"firstName" v8n:"notNull"`
LastName string `json:"lastName" v8n:"required, notNull"`
}
const jsonData = `{
"name": "Duro",
"gender": "MALE",
"tier": 3,
"dateOfBirth": "2000-01-13",
"mobileNumber": "0356874586",
"address": {
"city": "Tokyo",
"street": "Shibaura St"
},
"children":[
{
"title": "Mr",
"lastName": "Takayashi"
}
],
"isEmployed": false,
"requestedAt": "2022-01-10T03:30:12.639Z"
}`
var UserRequestValidator = valix.MustCompileValidatorFor(User{}, nil)
func main() {
user := User{}
ok, violations, _ := UserRequestValidator.ValidateStringInto(jsonData, &user)
if ok {
fmt.Println("Validation successful")
} else {
fmt.Println(fmt.Sprintf("Validation failed! (violations: %d)", len(violations)))
for _, v := range violations {
fmt.Printf("%s (property: '%s', path: '%s')\n", v.Message, v.Property, v.Path)
}
}
}
Go playground here: https://go.dev/play/p/3zrkZx97m-e
Disclosure: I am the author of Valix
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论