如何在Golang rest中输出json格式错误,特别是引用坏字段

时间:2019-06-30 08:13:13

标签: go error-handling

我有以下要求:REST API以以下格式返回错误:

Error format
422
{
    "name-of-field": [
        "can't be blank",
        "is too silly"
    ]
}

我的代码如下:

var PostFeedback = func(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    surveyId := params["id"]
    feedback := &models.Feedback{}
    err := json.NewDecoder(r.Body).Decode(feedback)
    if err != nil {
        jsonError := fmt.Sprintf(`{
            "%s": [
                "%s"
            ]
        }`, "errors", err)
        log.Printf("invalid input format, %v", jsonError)
        resp := map[string]interface{}{"error": jsonError}
        u.Respond(w, resp)
        return
    }

问题:

如何获取违规字段的名称?
我如何最好地满足要求?

1 个答案:

答案 0 :(得分:1)

encoding/json软件包不提供对“空白”或“傻”值的验证。仅当主体中的数据不是有效的json时,或者如果JSON中的字段类型(根据包的规范)与结构的字段类型不匹配时,它才会返回错误。您正在尝试解码该json。

第一种错误类型为json.SyntaxError,如果您得到此错误,则不一定总能满足您的要求,因为可能没有 no 个实际字段可用于响应,或者如果存在json字段,则它们及其值可能是完全有效的json,但错误的原因可能出在其他地方(请参见example)。

如果数据包含实际的json字段,但是具有非json值,则可以使用Offset类型的SyntaxError字段在数据中找到最接近的前一个字段流。使用strings.LastIndex,您可以实施天真解决方案以向后查找该字段。

data := []byte(`{"foobar": i'm not json}`)

err := json.Unmarshal(data, &T{})
se, ok := err.(*json.SyntaxError)
if !ok {
    panic(err)
}

field := string(data[:se.Offset])
if i := strings.LastIndex(field, `":`); i >= 0 {
    field = field[:i]
    if j := strings.LastIndex(field, `"`); j >= 0 {
        field = field[j+1:]
    }
}
fmt.Println(field) // outputs foobar

Playground link

注意:如您所见,为了能够查找字段,您需要有权访问数据,但是当您使用json.NewDecoder并传递时如果它直接位于请求的正文中,而无需先将其内容存储在某个地方,则在完成解码器的Decode方法后,您将无法访问该数据。这是因为正文是包裹在io.ReadCloser中的字节流,它不支持“倒带”,即您不能 re-read 解码器已经读取的字节。为避免这种情况,您可以使用ioutil.ReadAll读取正文的全部内容,然后使用json.Unmarshal进行解码。


第二种错误类型为json.UnmarshalTypeError。如果查看错误类型及其字段的文档,您将知道您所要做的就是键入断言返回的值,然后就完成了。 Example


在将json成功解码到您的结构后,将对“空白”和“傻”值进行验证。您的操作方式取决于您。例如,您可以使用专为验证结构而设计的第三方软件包,也可以自己实施内部解决方案,等等。我实际上对哪个是“最佳”一事没有意见,因此我可以帮你解决这个问题。

我能说的是,最基本的方法是简单地查看结构的每个字段,并根据该字段的要求检查其值是否有效。

>