func (app *application) writeJSON(w http.ResponseWriter, status int, data envelope, headers http.Header) error { js, err := json.MarshalIndent(data, "", " ") if err != nil { return err } // Append a newline to make it easier to view in terminal applications. js = append(js, '\n') // At this point, we know that we won't encounter any more errors before writing the response, // so it's safe to add any headers that we want to include. We loop through the header map and // add each header to the http.ResponseWriter header map. Note that it's OK if the provided // header map is nil. Go doesn't throw an error if you try to range over a nil map. for key, value := range headers { w.Header()[key] = value // w.Header().Set(key, value) } // iterator version // maps.Insert(w.Header(), maps.All(headers)) // Add the "Content-Type: application/json" header, then write the status code and JSON // response. w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) w.Write(js) return nil }
Using json.Encoder
func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) { data := map[string]string{ "hello": "world", }
// Set the "Content-Type: application/json" header on the response. w.Header().Set("Content-Type", "application/json")
// Use the json.NewEncoder() function to initialize a json.Encoder instance that // writes to the http.ResponseWriter. Then we call its Encode() method, passing in // the data that we want to encode to JSON (which in this case is the map above). If // the data can be successfully encoded to JSON, it will then be written to our // http.ResponseWriter. err := json.NewEncoder(w).Encode(data) if err != nil { app.logger.Error(err.Error()) http.Error(w, "The server encountered a problem and could not process your request", http.StatusInternalServerError) } }
Performance of json.Encoder and json.Marshal
Talking of speed, you might be wondering if there’s any performance difference between using json.Encoder and json.Marshal() . The short answer to that is yes… but the difference is small and in most cases you should not worry about it.
Additional JSON encoding nuances
Encoding things to JSON in Go is mostly quite intuitive. But there are a handful of behaviors which might either catch you out or surprise you when you first encounter them.
We’ve already mentioned a couple of these in this chapter (in particular — map entries being sorted alphabetically and byte slices being base-64 encoded), but I’ve included a full list in this appendix.