Idiomatic to use json.Unmarshal or json.Decode for http.Response

1,375 views
Skip to first unread message

st ov

unread,
Jun 19, 2018, 1:03:22 AM6/19/18
to golang-nuts
When unmarshaling a JSON http.Response

Is it more idiomatic to use ioutil.ReadAll and json.Unmarshal?

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var target Obj
err = json.Unmarshal(body, &target)
if err != nil {
log.Fatal(err)
}


Or json.Decode alone?

var target Obj
err = json.NewDecoder(resp.Body).Decode(&target)
if err != nil {
log.Fatal(err)

}


Most articles I've run across use ioutil.ReadAll and json.Unmarshal, but I've seen some that argue its more appropriate to use json.Decode.




Daniel Corbe

unread,
Jun 19, 2018, 2:27:33 AM6/19/18
to st ov, golang-nuts
Hooking Readers and Writers directly up to Decode and Encode is a very
simple solution to a lot of problems but as I’ve come to discover, it
doesn’t cover corner cases. You may need to Marshal/Unmarshal as an
intervening step to cover such corner cases. For example, there are times
when you may need to make minor changes to the data in-flight for protocol
compliance reasons. encoder/xml and XMPP come to mind as a good example
and in fact I was talking about this very issue just yesterday.

Best,
Daniel

st ov

unread,
Jun 19, 2018, 9:49:13 PM6/19/18
to golang-nuts
Pointed out some pitfalls of using json.Decode

So then you're saying it's idiomatic and best practice to use ioutil.ReadAll and json.Unmarshal when reading a JSON body?

Daniel Corbe

unread,
Jun 19, 2018, 10:56:23 PM6/19/18
to st ov, golang-nuts
It’s an old article. There have been improvments to json.Decode since the
Go 1.6 days.

But conclusion of the article is still correct. Don’t expect json.Decode
to cover every conceivable corner case.
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.


st ov

unread,
Jun 20, 2018, 12:42:48 AM6/20/18
to golang-nuts
Thanks Daniel, I'll stick to json.Unmarshal for http.Response bodies.

Amnon Baron Cohen

unread,
Jun 21, 2018, 2:21:19 AM6/21/18
to golang-nuts
I generally use `json.NewDecoder(resp.Body).Decode()`
because I generally prefer simpler shorter code to 
longer more complex code.

The claim in the blog post that the decoder does not drain the
request.Body preventing connection reuse does not match my observation.
(I only tested on 1.10).

I would generally avoid calling `log.Fatal()` within production code.
Better to log and return a 400 error.

messju mohr

unread,
Jun 21, 2018, 12:40:08 PM6/21/18
to Amnon Baron Cohen, golang-nuts
On Wed, Jun 20, 2018 at 11:21:19PM -0700, Amnon Baron Cohen wrote:
[...]
> The claim in the blog post that the decoder does not drain the
> request.Body preventing connection reuse does not match my observation.
> (I only tested on 1.10).

The blog post clearly states, that this was fixed in go1.7.

> > [1]https://ahmet.im/blog/golang-json-decoder-pitfalls/

st ov

unread,
Jun 24, 2018, 9:21:39 PM6/24/18
to golang-nuts
So there maybe isn't any consensus on the right method for reading a standard JSON body from an http.Response?

Daniel Corbe

unread,
Jun 25, 2018, 1:44:03 PM6/25/18
to st ov, golang-nuts
I think the consensus is if your app is simple and you need a quick and
dirty solution, you should be using json.Decode/Encode. If you want more
control over the JSON being streamed, use json.Marshal/Unmarshal.
Reply all
Reply to author
Forward
0 new messages