douweng7083 2019-06-30 08:13
浏览 128
已采纳

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

I have the following requirement: return errors from a REST API in the following format:

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

My code looks like this:

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
    }

Questions:

How do I get the names of the offending fields?
How do I satisfy the requirement best?

  • 写回答

1条回答 默认 最新

  • douzi1350 2019-06-30 12:57
    关注

    The encoding/json package doesn't provide validation for "blank", nor "silly" values. It will return an error only if the data in the body is not a valid json, or if the field types in the json do not, according to the package's spec, match the field types of the structure into which you're trying to decode that json.

    The 1st type of error would be the json.SyntaxError, if you get this it is not always possible to satisfy your requirements since there may be no actual fields which you could use in your response, or if there are json fields, they, and their values, may be perfectly valid json, but the cause of the error may lie elsewhere (see example).

    In cases where the data holds actual json fields but it has, for example, non-json values you could use the Offset field of the SyntaxError type to find the closest preceding field in the data stream. Using strings.LastIndex you can implement a naive solution to look backwards for the field.

    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

    NOTE: As you can see, for you to be able to look for the field, you need to have access to the data, but when you're using json.NewDecoder and passing it the request's body directly, without first storing its contents somewhere, you'll loose access to that data once the decoder's Decode method is done. This is because the body is a stream of bytes wrapped in a io.ReadCloser that does not support "rewinding", i.e. you cannot re-read bytes that the decoder already read. To avoid this you can use ioutil.ReadAll to read the full contents of the body and then json.Unmarshal to do the decoding.


    The 2nd type of error would be the json.UnmarshalTypeError. If you look at the documentation of the error type and its fields you'll know that all you need to do is to type assert the returned value and you're done. Example


    Validation against "blank" and "silly" values would be done after the json has been successfully decoded into your structure. How you do that is up to you. For example you could use a 3rd party package that's designed for validating structs, or you can implement an in-house solution yourself, etc. I actually don't have an opinion on which one of them is the "best" so I can't help you with that.

    What I can say is that the most basic approach would be to simply look at each field of the structure and check if its value is valid or not according to the requirements for that field.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥15 python天天向上类似问题,但没有清零
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 C#调用python代码(python带有库)
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)