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

Wil*_*zzi 5 arrays error-handling json go

我有一系列错误(错误类型),但是当我尝试以 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
)
Run Code Online (Sandbox Code Playgroud)

在我的控制器中:

err := person.Validate()
c.JSON(422, gin.H{"errors" : err})
Run Code Online (Sandbox Code Playgroud)

我的输出:

{"errors":"[{}]"}
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 5

error类型是具有单个的接口Error()方法,但它不是特殊的json包(Error()方法不被调用就可以了)。

但是,error值可以保存静态类型的值,这些值可以很好地编组,或者它们可以通过实现json.Marshaler. 简单errorstring通过调用它的Error()方法来转换一个to意味着我们不遵守自定义封送处理逻辑。

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

  • 检查错误值是否实现json.Marshaler,如果是,则让它自行编组
  • else 作为后备案例调用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)
}
Run Code Online (Sandbox Code Playgroud)

这就是您可以使用它的方式:

err := person.Validate()
c.JSON(422, gin.H{"errors" : JSONErrs(err)})
Run Code Online (Sandbox Code Playgroud)

让我们测试一下我们的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})
}
Run Code Online (Sandbox Code Playgroud)

和测试代码:

errs := []error{
    errors.New("first"),
    errors.New("second"),
    MyErr{16},
}

data, err := json.Marshal(JSONErrs(errs))
fmt.Println(string(data), err)
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

["first","second",{"Type":"MyErr","Error":"Invalid input!","AtLine":16}] <nil>
Run Code Online (Sandbox Code Playgroud)


1la*_*ann 2

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

fmt.Println和等函数log.Println会自动解析error类型以显示来自 的消息Error(),但 JSON 库却不会。解决此问题的最简单方法是将错误消息转换为[]errora[]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})
Run Code Online (Sandbox Code Playgroud)