How to serve up a JSON response using Go?

JsonGo

Json Problem Overview


Question: Currently I'm printing out my response in the func Index like this fmt.Fprintf(w, string(response)) however, how can I send JSON properly in the request so that it maybe consumed by a view?

package main

import (
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"log"
	"encoding/json"
)

type Payload struct {
	Stuff Data
}
type Data struct {
	Fruit Fruits
	Veggies Vegetables
}
type Fruits map[string]int
type Vegetables map[string]int


func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	response, err := getJsonResponse();
	if err != nil {
		panic(err)
	}
	fmt.Fprintf(w, string(response))
}


func main() {
	router := httprouter.New()
	router.GET("/", Index)
	log.Fatal(http.ListenAndServe(":8080", router))
}

func getJsonResponse()([]byte, error) {
	fruits := make(map[string]int)
	fruits["Apples"] = 25
	fruits["Oranges"] = 10

	vegetables := make(map[string]int)
	vegetables["Carrats"] = 10
	vegetables["Beets"] = 0

	d := Data{fruits, vegetables}
	p := Payload{d}

	return json.MarshalIndent(p, "", "  ")
}

Json Solutions


Solution 1 - Json

You can set your content-type header so clients know to expect json

w.Header().Set("Content-Type", "application/json")

Another way to marshal a struct to json is to build an encoder using the http.ResponseWriter

// get a payload p := Payload{d}
json.NewEncoder(w).Encode(p)

Solution 2 - Json

Other users were commenting that the Content-Type is plain/text when encoding.
You have to set the content type with w.Header().Set() first, then write the HTTP response code with w.WriteHeader().

If you call w.WriteHeader() first, then call w.Header().Set() after you will get plain/text.

An example handler might look like this:

func SomeHandler(w http.ResponseWriter, r *http.Request) {
    data := SomeStruct{}
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(data)
}

Solution 3 - Json

You can do something like this in you getJsonResponse function -

jData, err := json.Marshal(Data)
if err != nil {
	// handle error
}
w.Header().Set("Content-Type", "application/json")
w.Write(jData)

Solution 4 - Json

In gobuffalo.io framework I got it to work like this:

// say we are in some resource Show action
// some code is omitted
user := &models.User{}
if c.Request().Header.Get("Content-type") == "application/json" {
    return c.Render(200, r.JSON(user))
} else {
    // Make user available inside the html template
    c.Set("user", user)
    return c.Render(200, r.HTML("users/show.html"))
}

and then when I want to get JSON response for that resource I have to set "Content-type" to "application/json" and it works.

I think Rails has more convenient way to handle multiple response types, I didn't see the same in gobuffalo so far.

Solution 5 - Json

You may use this package renderer, I have written to solve this kind of problem, it's a wrapper to serve JSON, JSONP, XML, HTML etc.

Solution 6 - Json

This is a complement answer with a proper example:

func (ch captureHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodPost:
	    body, err := ioutil.ReadAll(r.Body)
	    if err != nil {
		    http.Error(w, fmt.Sprintf("error reading request body, %v", err), http.StatusInternalServerError)
		    return
	    }
	    ...do your stuff here...
    case http.MethodGet:
	    w.Header().Set("Content-Type", "application/json")
	    err := json.NewEncoder(w).Encode( ...put your object here...)
	    if err != nil {
		    http.Error(w, fmt.Sprintf("error building the response, %v", err), http.StatusInternalServerError)
		    return
	    }
    default:
	    http.Error(w, fmt.Sprintf("method %s is not allowed", r.Method), http.StatusMethodNotAllowed)
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArmeen HarwoodView Question on Stackoverflow
Solution 1 - Jsondm03514View Answer on Stackoverflow
Solution 2 - JsonDaniel R.View Answer on Stackoverflow
Solution 3 - JsonpoorvaView Answer on Stackoverflow
Solution 4 - JsonAleks TkachenkoView Answer on Stackoverflow
Solution 5 - Jsonuser3679289View Answer on Stackoverflow
Solution 6 - JsonMircea StanciuView Answer on Stackoverflow