简体   繁体   English

Golang:验证字符串类型的结构字段为特定值之一

[英]Golang: Validate Struct field of type string to be one of specific values

golang version: 1.18.3 golang 版本: 1.18.3

validator: github.com/go-playground/validator/v10验证器: github.com/go-playground/validator/v10

I want to validate an incoming JSON payload after loaded into nested struct data structure.我想在加载到嵌套结构数据结构后验证传入的 JSON 有效负载。 Here's my incoming JSON payload,这是我传入的 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"
}

Here's my user.go file,这是我的 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"`
    }

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.发生这种情况是因为 Go 将空字符串分配给 User.PreferredContactMethod 结构字段。 Since PreferredContactMethod is NOT a required field, I DON'T want to see this validation error when json payload doesn't have it.由于PreferredContactMethod不是必填字段,因此当 json 有效负载没有它时,我不想看到此验证错误。 How can I avoid this error message when the json payload doesn't have preferredContactMethod field?当 json 有效负载没有preferredContactMethod字段时,如何避免此错误消息?

If you have better alternatives to achieve this validation, happy to hear them as well.如果您有更好的选择来实现此验证,也很高兴听到它们。

Here's the code in Go Playground这是Go Playground 中的代码

Utilize omitempty along with oneof to make the validator library ignore empty or unset values.使用omitemptyoneof使验证器库忽略空值或未设置值。

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"`
    }

Using https://github.com/marrow16/valix ( https://pkg.go.dev/github.com/marrow16/valix ) it could be achieved with the following:使用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 here: https://go.dev/play/p/3zrkZx97m-e去游乐场: https ://go.dev/play/p/3zrkZx97m-e

Disclosure: I am the author of Valix披露:我是 Valix 的作者

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM