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 不同系统编译兼容问题
  • ¥100 三相直流充电模块对数字电源芯片在物理上它必须具备哪些功能和性能?
  • ¥30 数字电源对DSP芯片的具体要求
  • ¥20 antv g6 折线边如何变为钝角
  • ¥30 如何在Matlab或Python中 设置饼图的高度
  • ¥15 nginx中的CORS策略应该如何配置
  • ¥30 信号与系统实验:采样定理分析
  • ¥100 我想找人帮我写Python 的股票分析代码,有意请加mathtao
  • ¥20 Vite 打包的 Vue3 组件库,图标无法显示
  • ¥15 php 同步电商平台多个店铺增量订单和订单状态