This is a pretty common task: encode JSON and send it to a server, decode JSON on the server, and vice versa. Amazingly, the existing resources on how to do this aren't very clear. So let's walk through each case, for the following simple User object:

type User struct { Id string Balance uint64 }

Sending JSON in the body of a POST/PUT request

Let's start with the trickiest one: the body of a Go's http.Request is an io.Reader , which doesn't fit well if you have a struct - you need to write the struct first and then copy that to a reader.

func main () { u := User { Id : "US123" , Balance : 8 } b := new ( bytes . Buffer ) json . NewEncoder ( b ). Encode ( u ) res , _ := http . Post ( "https://httpbin.org/post" , "application/json; charset=utf-8" , b ) io . Copy ( os . Stdout , res . Body ) }

Decoding JSON on the server

Let's say you're expecting the client to send JSON data to the server. Easy, decode it with json.NewDecoder(r.Body).Decode(&u) . Here's what that looks like with error handling:

func main () { http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) { var u User if r . Body == nil { http . Error ( w , "Please send a request body" , 400 ) return } err := json . NewDecoder ( r . Body ). Decode ( & u ) if err != nil { http . Error ( w , err . Error (), 400 ) return } fmt . Println ( u . Id ) }) log . Fatal ( http . ListenAndServe ( ":8080" , nil )) }

Encoding JSON in a server response

Just the opposite of the above - call json.NewEncoder(w).Encode(&u) to write JSON to the server.

func main () { http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) { u := User { Id : "US123" , Balance : 8 } json . NewEncoder ( w ). Encode ( u ) }) log . Fatal ( http . ListenAndServe ( ":8080" , nil )) }

Reading a JSON response from the server.

This time you're going to read the response body in the client, after making the request.

func main () { u := User { Id : "US123" , Balance : 8 } b := new ( bytes . Buffer ) json . NewEncoder ( b ). Encode ( u ) res , _ := http . Post ( "https://httpbin.org/post" , "application/json; charset=utf-8" , b ) var body struct { // httpbin.org sends back key/value pairs, no map[string][]string Headers map [ string ] string `json:"headers"` Origin string `json:"origin"` } json . NewDecoder ( res . Body ). Decode ( & body ) fmt . Println ( body ) }

That's it! I hope it helps you a lot. Note that we only had to encode/decode the response to a byte array one time - in every other case we passed it directly to the reader/writer, which is one of the really nice things about Go, and interfaces - in most cases it's really easy to pass around streams, instead of having to deal with the intermediate steps.

Liked what you read? I am available for hire.