【问题标题】:Validate field based on value of a different field with validator.v2使用 validator.v2 根据不同字段的值验证字段
【发布时间】:2020-07-14 00:44:06
【问题描述】:

我有以下(简化的)结构:

type newAppRegister struct {
    SomeFlag       *bool    `json:"someflag" validate:"nonnil"`
    ComputeLevel   string   `json:"compute-level" validate:"computelevelvalidator"`
}

computelevelvalidator 是一些验证函数。

我希望如果 SomeFlag 为 false,则需要 ComputeLevel 并运行他的验证功能。

一种可能的解决方案是创建一个静态变量,并将其设置在 SomeFlag 的自定义验证函数中,例如:

var someFlag bool

func someFlagValidator(v interface{}, param string) error {
    st := reflect.ValueOf(v)
    if st.Kind() != reflect.Bool {
        return fmt.Errorf("must be bool")
    }
    someFlag = st.Bool()
    return nil
}

然后在computelevelvalidator 中可以根据他的值进行调节。

但由于这是一个 REST API,它每秒可能会收到大量调用,我不确定使用这个静态变量是否有效(我担心竞争条件 - 但我不太确定它)。

我正在使用 go1.11 和验证包gopkg.in/validator.v2(版本gopkg.in/validator.v2 v2.0.0-20190827175613-1a84e0480e5b)。

【问题讨论】:

  • 你为什么要使用反射?
  • @Flimzy 复制自文档godoc.org/gopkg.in/validator.v2#hdr-Custom_validation_functions 这似乎是他们编写自定义验证器的方式
  • 我看不出有什么理由不使用类型断言。它会更有效率,也更容易阅读:v, ok := v.(bool); if !ok { return fmt.Errorf("must be bool") } someFlag = v; return nil
  • @Flimzy 你说得有道理!谢谢

标签: rest validation go


【解决方案1】:

所以首先:是的,使用这个静态(全局)变量将是并发使用/访问的问题。这不是要走的路。

如果您的验证逻辑是上下文相关的(如您所说:如果标志为 false,则某些限制适用于另一个字段),那么实现一个简单的 Validate 函数非常简单。我知道你使用的包支持这种类型的东西,但是外部包几乎总是被设计成相当通用的。至少你最终会执行类型断言。上次我检查过,您仍然需要显式调用验证 validator.Validate(),那么为什么不将其移至您类型的方法中呢?

type newAppRegister struct {} // your type

func (n newAppRegister) Validate() error {
    if err := validator.Validate(n); err != nil {
        return err
    }
    // at this point, we now the flag field isn't nit, because it passed validation
    if !*n.SomeFlag {
        // validate ComputeLevel here
    }
    return nil
}

不需要类型断言,更不用说反射了。只有这两个字段,我什至认为根本不需要验证器包。您只需使用标准 JSON 标签即可完成相同的操作:

type Foo struct {
    SomeFlag     *bool   `json:"some_flag,omitempty"`
    ComputeLevel string  `json:"compute_level"`
}

func (f Foo) Validate() error {
    if f.SomeFlag == nil {
        return ErrSomeFlagRequired
    }
    if !*f.SomeFlag {
        // validate ComputeLevel
    }
    return nil
}

使用起来相当简单:

f := Foo{}
if err := json.Unmarshal([]byte(payload), &f); err != nil {
    // some shady JSON was submitted
}
if err := f.Validate(); err != nil {
    // JSON was technically valid, but payload made no sense
}
// handle valid request

【讨论】:

  • 通过快速阅读文档,我在包中找不到这种验证。最终使用了您的建议。谢谢!
猜你喜欢
  • 2019-07-11
  • 2018-09-04
  • 1970-01-01
  • 2017-02-28
  • 1970-01-01
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多