1

I'm starting to go crazy trying to get Go to decode this json request body. Here's a sample request:

curl -X POST -d "{\"username\":\"foo\", \"password\":\"bar\"}" http://localhost:3000/users

And here's my handler:

mux.HandleFunc("/users", func(rw http.ResponseWriter, req *http.Request) {
        var body struct {
            username string
            password string
        }

        // buf := make([]byte, req.ContentLength)
        // req.Body.Read(buf)
        // fmt.Println(string(buf))
        //
        // The above commented out code will correctly print:
        // {"username":"foo", "password":"bar"}

        err := json.NewDecoder(req.Body).Decode(&body)
        if err != nil {
            rw.WriteHeader(http.StatusNotAcceptable)
            return
        }

        fmt.Printf("%+v\n", body)
        // prints -> {username: password:}
})

Like the comment suggests, I can verify that req.Body is indeed correct -- but for whatever reason, json.NewDecoder(req.Body).Decode(&body) never fills out the fields of body.

Any help would be greatly appreciated!

Zach Young
  • 10,137
  • 4
  • 32
  • 53
Cody
  • 1,178
  • 3
  • 12
  • 26
  • The duplicate this question is closed as a target of has nothing to do with JSON and the semantics of struct fields in the json pkg. This question _exactly_ represents the problem I had and the accepted answer below is _exactly_ the solution. – Zach Young Jun 17 '22 at 17:00

1 Answers1

5

The problem is that the json decoder does not deal with private struct fields. The fields in your body structs are private.

Rewrite it like so and it will work:

 var body struct {
        Username string `json:"username"` 
        Password string `json:"password"`
 }

basically the json:"username" is a way to tell the json decoder how to map the json name of the object to the struct name. In this instance, for decoding only, it is not necessary - the json decoder is smart enough to make the translation of the upper/lower case.

But if you use the object to encode json as well, you need it, or you'll have upper case field names in the resulting json.

You can use the json struct tags for a few more useful things, like omitting empty field from encoded json, or skipping fields entirely.

You can read more about the JSON struct tags in the documentation for json.Marshal: http://golang.org/pkg/encoding/json/#Marshal

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • 1
    Thank you so much! I thought I was being clever by making the fields lowercase, so I wouldn't have to specify the json name, but it makes so much sense now why that could never work. – Cody Feb 21 '15 at 18:24
  • I think this is the relevant line in the documentation that's our clue to use tags for lowercased names in the source JSON: _Struct values encode as JSON objects. Each **exported** struct field becomes a member of the object, using the field name as the object key, unless the field is omitted for one of the reasons given below._ (emph. added) Granted, that's for marshaling, but the same goes in reverse for decoding (unmarshaling)? – Zach Young Jun 17 '22 at 16:50