【问题标题】:Request body validation with http Mux使用 http Mux 请求正文验证
【发布时间】:2020-07-25 14:18:22
【问题描述】:

我正在尝试使用 Go 和 Mux 构建 API。我正在尝试验证传入的请求。我尝试在 Struct 上使用标签并使用 Go Validator 对其进行验证。

这是我的结构

type Address struct {
    Street string `validate:"required"`
    City   string `validate:"required"`
    Phone  string `validate:"required"`
}

我的问题是

  • 有一个POST 端点,所有字段都将通过并且验证不会失败。但是,还有另一个 PATCH 端点,并非 Address 结构的所有字段都会通过,因此验证失败。

例如。 API 可能会收到

{
  "Street": "Dummy"
}

在这种情况下验证POSTPATCH 请求的最佳方法是什么。

【问题讨论】:

    标签: go mux


    【解决方案1】:

    在 PATCH 端点中使用具有不同(如果有)验证标签的不同类型。之后转换为地址:

    // Same underlying type as Address, but no validation tags
    var x struct {
        Street string
        City   string
        Phone  string
    }
    
    // Decode request into x, then:
    
    addr := Address(x)
    

    【讨论】:

    • 谢谢。在这种情况下,如果我们添加一个新字段,那么我们必须在所有正确创建的类型中更改它。
    • 是的。编译器会确保你不会忘记一个。
    【解决方案2】:

    改变我的答案

    我已经对您的案例进行了测试并找到了解决方案,您必须使用struct level validation。这是我在您的案例中的功能:

    func PostRequestValidation(sl validator.StructLevel) {
    
        address := sl.Current().Interface().(Address)
    
        jsonMarshal, _ := json.Marshal(address)
        var m map[string]interface{}
        _ = json.Unmarshal(jsonMarshal, &m)
        for key, val := range m {
            if len(fmt.Sprintf("%s", val)) == 0 {
                sl.ReportError(val, key, key, "post", "")
            }
        }
    }
    
    func PutRequestValidation(sl validator.StructLevel) {
    
        address := sl.Current().Interface().(Address)
    
        isValid := false
    
        jsonMarshal, _ := json.Marshal(address)
        var m map[string]interface{}
        _ = json.Unmarshal(jsonMarshal, &m)
        for _, val := range m {
            if len(fmt.Sprintf("%s", val)) > 0 {
                isValid = true
            }
        }
    
        if !isValid {
            sl.ReportError(address, "address", "Adress", "put", "")
        }
    }
    

    您只需在每个验证请求上注册

        // ON POST REQUEST
        validate = validator.New()
        validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
            name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
            if name == "-" {
                return ""
            }
            return name
        })
        validate.RegisterStructValidation(PostRequestValidation, Address{})
    
        // ON PUT REQUEST
        validate = validator.New()
        validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
            name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
            if name == "-" {
                return ""
            }
            return name
        })
        validate.RegisterStructValidation(PutRequestValidation, Address{})
    

    您可以从我的source code 复制以获得更详细的源代码。

    【讨论】:

    • 感谢您的指点。但是使用上述方法之一会使 POST 请求无效,因为在 POST 中我们需要所有字段。这里有什么建议吗?
    • aha,所以如果你需要多个这样的条件,你可以使用 Or 运算符。以街道字符串 validate:"required|required_without_all" 为例。替换每个字段的验证。我将根据此评论更新我的答案。您应该根据评论更新您的问题。
    • 我已经更新了这个问题。现在说清楚了:) 这仍然不起作用 - or 条件无法正确评估。说PATCH 我不需要City,但POST 需要City。即使未提供 City,使用 or 条件也可以验证 POST 有效负载。
    • 嗨,我希望你可以根据你的需要修改我的代码,对不起我之前的回答,它具有误导性。如果您回答了这个问题,请不要忘记将此问题标记为已解决。
    【解决方案3】:

    找到这个库 - govalidator。这允许根据要求为每个请求创建规则。对于 POST 请求,创建一组规则,所有字段均为必填项。对于 PATCH 请求,创建所有字段为可选的规则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      相关资源
      最近更新 更多