普通网友 2017-02-22 11:50
浏览 131
已采纳

Golang验证器多字段依赖

I'd like to validate the following structure :

type CarModel struct {
  gorm.Model
  OwnerID    int    `json:"ownerid" validate:"nonzero"`
  Type       string `json:"type" validate:"regexp=(?)(A|B)"`
  A        string `json:"url" validate:"isurl"`
  B         string `json:"ip" validate:"isip"`
}

I would like to validate A and B depending on Type, if type = A then A must exist and must be a URL BUT B must not exist if type = B then A must not exist and B must be an IP

is this possible with validator ?

I did try custom validation but I cannot find a way to see type value :

func checkB(v interface{}, param string) error {
    theB := reflect.ValueOf(v)
    if theB.Kind() != reflect.String {
        return validator.ErrUnsupported
    }
    //check if B is an IP
    ipcool := net.ParseIP(theB.String())
    if ipcool == nil {
        return errors.New("B : ip incorrecte " + theB.String())
    }
    return nil
}

Upon the answer of Alex Nichol, I would like first to thank you for your help.

If I understood correctly, I would have to iterate through all the "validate" fields, to keep a trace of the value of TYPE, A and B and then to check them depending on TYPE ...

I did this :

func checkMonitor(v interface{}) error {
    var mytype string
    var myA string
    var myB string

    val := reflect.ValueOf(v)
    // Iterate through fields
    for i := 0; i < val.NumField(); i++ {
        // Lookup the validate tag
        field := val.Type().Field(i)
        tags := field.Tag
        _, ok := tags.Lookup("validate")
        if !ok {
            // No validate tag.
            continue
        }

        // Get the value of the field.
        fieldValue := val.Field(i)

        switch field.Name {
        case "Type":
            mytype = fieldValue.Interface()
        case "A":
            myA = fieldValue.Interface()
        case "B":
            myB = fieldValue.Interface()
        }
        // Validation logic here.
        //fmt.Println("field", field.Name, "has validate tag", validate, "and value", fieldValue.Interface())
    }
    if mytype == "A" {
        if myA == "" {
            return errors.New("A vide et type A")
        }
        ipcool := net.ParseIP(myA)
        if ipcool == nil {
            return errors.New("A incorrecte " + myA)
        }
    } else if mytype == "HTML" {
        if myB == "" {
            return errors.New("B vide et type B")
        }
        _, urlpascool := url.ParseRequestURI(myB)
        if urlpascool != nil {
            return errors.New("B incorrecte " + myB)
        }
    }
    return nil
}

but got an error on the mytype, myA and myB in the switch case :

cannot use fieldValue.Interface() (type interface {}) as type string in assignment: need type assertion

EDIT : just needed to use my brain :

switch field.Name {
case "Type":
   mytype = fieldValue.String()
case "A":
   myA = fieldValue.String()
case "B":
   myB = fieldValue.Interface()
}
  • 写回答

2条回答 默认 最新

  • drox90250557 2017-02-22 13:53
    关注

    You probably want to use reflection to iterate over the fields of the struct, get the validate tag for each field, and check the field. This means you'll have to do validation on a struct level. Otherwise, if you pass something like myInstance.OwnerID to a function, you'll lose the tag associated with it.

    This code loops through the fields of a struct and gets the validate tag for each:

    func checkStruct(v interface{}) error {
        val := reflect.ValueOf(v)
    
        // Iterate through fields
        for i := 0; i < val.NumField(); i++ {
            // Lookup the validate tag
            field := val.Type().Field(i)
            tags := field.Tag
            validate, ok := tags.Lookup("validate")
            if !ok {
                // No validate tag.
                continue
            }
    
            // Get the value of the field.
            fieldValue := val.Field(i)
    
            // Validation logic here.
            fmt.Println("field", field.Name, "has validate tag", validate, "and value",
                fieldValue.Interface())
        }
        return nil
    }
    

    For example, we could pass it the following CarModel:

    checkStruct(CarModel{
        OwnerID: 2,
        Type:    "B",
        A:       "http://google.com",
        B:       "192.168.1.1",
    })
    

    and it would print out the following:

    field OwnerID has validate tag nonzero and value 2
    field Type has validate tag regexp=(?)(A|B) and value B
    field A has validate tag isurl and value http://google.com
    field B has validate tag isip and value 192.168.1.1
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c