如何在Go中将错误数组转换为JSON

9

我有一个错误数组(错误类型),但当我试图以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":"[{}]"}
2个回答

7
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})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接