【问题标题】:How to convert array of errors to JSON in Go如何在 Go 中将错误数组转换为 JSON
【发布时间】:2017-05-15 12:50:23
【问题描述】:

我有一个错误数组(错误类型),但是当我尝试以 JSON 格式返回客户端时,它是空的。

它是这样创建的:

var (
    ErrEmptyName = errors.New("Nome não pode ser vázio")
    ErrInvalidType = errors.New("Tipo de pessoa inválido")
)

func (p Person) Validate() []error {

    var errors []error

    if govalidator.IsNull(p.Name) {
        errors = append(errors, ErrEmptyName)
    }

    if p.Type != "F" && p.Type != "J" {
        errors = append(errors, ErrInvalidType)
    }

    return errors
)

在我的控制器中:

err := person.Validate()
c.JSON(422, gin.H{"errors" : err})

我的输出:

{"errors":"[{}]"}

【问题讨论】:

    标签: arrays json go error-handling


    【解决方案1】:

    error 类型是一个带有单个Error() 方法的接口,但它对json 包来说并不特殊(不会调用Error() 方法)。

    但是,error 值可能包含静态类型的值,这些值可以很好地编组,或者它们可以通过实现 json.Marshaler 来定义自己的编组逻辑。简单地通过调用 Error() 方法将 error 转换为 string 意味着我们不遵守自定义封送逻辑。

    所以我建议创建我们自己的错误切片类型,我们可以在其上实现我们的编组逻辑,应该是:

    • 检查错误值是否实现json.Marshaler,如果是,让它自己编组
    • 作为备用案例调用 error.Error() 以“获取”string,它可以轻松编组

    这就是它的样子:

    type JSONErrs []error
    
    func (je JSONErrs) MarshalJSON() ([]byte, error) {
        res := make([]interface{}, len(je))
        for i, e := range je {
            if _, ok := e.(json.Marshaler); ok {
                res[i] = e // e knows how to marshal itself
            } else {
                res[i] = e.Error() // Fallback to the error string
            }
        }
        return json.Marshal(res)
    }
    

    你可以这样使用它:

    err := person.Validate()
    c.JSON(422, gin.H{"errors" : JSONErrs(err)})
    

    让我们测试一下我们的JSONErrs。我们还使用了一个自定义错误类型,它实现了自定义编组逻辑:

    type MyErr struct{ line int }
    
    func (me MyErr) Error() string { return "Invalid input!" }
    
    func (me MyErr) MarshalJSON() ([]byte, error) {
        return json.Marshal(
            struct {
                Type, Error string
                AtLine      int
            }{"MyErr", me.Error(), me.line})
    }
    

    以及测试代码:

    errs := []error{
        errors.New("first"),
        errors.New("second"),
        MyErr{16},
    }
    
    data, err := json.Marshal(JSONErrs(errs))
    fmt.Println(string(data), err)
    

    输出(在Go Playground 上试试):

    ["first","second",{"Type":"MyErr","Error":"Invalid input!","AtLine":16}] <nil>
    

    【讨论】:

      【解决方案2】:

      error 类型是一个接口,它必须实现一个Error() 方法,该方法将错误消息作为字符串返回。这是在这里定义的:https://golang.org/pkg/builtin/#errorerror 类型是接口的原因是允许error 类型可以进行类型转换以检索更详细的信息。

      fmt.Printlnlog.Println 这样的函数会自动解析error 类型以显示来自Error() 的消息,但是JSON 库不会。解决此问题的最简单方法是将[]error 中的错误消息转换为[]string 并对其进行编码。

      这里有一些使用 for 循环的示例代码。

      errs := person.Validate()
      strErrors := make([]string, len(errs))
      
      for i, err := range errs {
          strErrors[i] = err.Error()
      }
      
      c.JSON(422, gin.H{"errors" : strErrors})
      

      【讨论】:

        猜你喜欢
        • 2012-12-14
        • 2018-10-28
        • 2023-03-22
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 2021-10-24
        • 1970-01-01
        • 2021-01-16
        相关资源
        最近更新 更多