Search code examples
jsongo

Why do I get EOF error if no body is passed but get default values if I provide "{}" in GO using json.NewDecoder(r.Body).decode?


When I make a request to the server without passing and value in the body I get and error massage as: EOF.

But I get default values in these fields if I pass a body like { }

How does this behavior work ?

func (app *application) createMovieHandler(w http.ResponseWriter, r *http.Request) {

    var input struct {
        Title   string   `json:"title"`
        Year    int32    `json:"year"`
        Runtime int32    `json:"runtime"`
        Genres  []string `json:"genres"`
    }

    fmt.Println(r.Body)
    err := json.NewDecoder(r.Body).Decode(&input)
    if err != nil {
        app.errorResponse(w, r, http.StatusBadRequest, err.Error())
        return
    }
    fmt.Fprintf(w, "%+v\n", input)
}

I expected to get Zero Values on both of the cases.


Solution

  • You get an EOF error in both cases.

    EOF is returned immediately with an empty body because the decoder finds no JSON value to decode before reaching the reader's end. This call will not modify the destination variable since no JSON was found to decode into that value.

    When you pass a body containing {}, the decoder will decode that value successfully. However, since the JSON object contains no properties, decoding it will not affect the destination variable.

    {} is not equivalent to { "title": "" }

    If you were to attempt to decode a further value using the same decoder, you would then get the EOF since the end of the reader was reached as a result of decoding the previous value. Again, the destination variable is not affected.

    The only scenario in which decoding JSON value will modify the existing fields in a destination variable is when the JSON being decoded contains properties that correspond to those fields.

    I have created a go playground to illustrate the above:

    func main() {
        dest := struct {
            Title string
        }{
            Title: "as initialised",
        }
        fmt.Println("decode empty: ", json.NewDecoder(bytes.NewReader([]byte{})).Decode(&dest))
        fmt.Println("dest.Title: ", dest.Title)
    
        zdecoder := json.NewDecoder(bytes.NewReader([]byte("{}")))
        fmt.Println("decode zero (1st):", zdecoder.Decode(&dest))
        fmt.Println("dest.Title: ", dest.Title)
        fmt.Println("decode zero (2nd)", zdecoder.Decode(&dest))
        fmt.Println("dest.Title: ", dest.Title)
    
        fmt.Println("decode zerotitle: ", json.NewDecoder(bytes.NewReader([]byte(`{"title":""}`))).Decode(&dest))
        fmt.Println("dest.Title: ", dest.Title)
    }