Serving JSON response in server

Hi All

I would like to know how I could serve json response in a go server. This is what I am doing currently which throws an error in the browser(Mozilla) when I check for response.
Error message:- SyntaxError: JSON.parse unexpected end of line

This makes me believe the data part of response was not properly json encoded.

This is my Json response –
For the purpose of this forum I have altered the structure name and content. But it is pretty much the same.

func ServeJSON(w http.ResponseWriter, r *http.Request, code int) {              
    w.Header().Set("Content-Type", "application/json")                          
        w.WriteHeader(code)                                                     
        profile := Profile{"Alex", []string{"snowboarding", "programming"}}     
                                                                                
    js, err := json.Marshal(profile)                                            
        if err != nil {                                                         
            http.Error(w, err.Error(), http.StatusInternalServerError)          
                return                                                          
        }                                                                       
    w.Header().Set("Content-Type", "application/json")                          
        w.Write(js)                                                             
}                                                                               

I’m not sure it’s the root cause, but you’re setting the header twice and include a writeheader call between them. I’d remove the first header set and the writeheader to see what happens. Also, look at the output with something like curl -v to get more insight into what your server actually sends.

Also, make sure the fields in Profile are public (they start with an upper case letter).

Have you tried printing the json? like log.Println(string(js)) and checked the output? I’d also guess that private fields in the struct is the reason

Hi @dfc

Ya the fields start with an uppercase –
Something like this.

type Profile struct {
  Name    string       
  Hobbies []string
}

Hi @jon

By default does it become private here?

type Profile struct {
  Name    string        
  Hobbies []string
} 

I am not able to use curl to test it as I am using this for FB login. The struct content which I am showing is not the exact one that I am using though. But basically I am trying to send a token back to the user for Facebook login. So can’t test with curl. This has to be the response on FB login. Can’t simulate exactly @calmh. But will try printing and testing it. Thanks a lot.

Hey @sandyethadka, after putting together a simple example using most of your code untouched, I am not receiving any errors in browser, lastly setting the content-type twice is slightly strange and also you should be making sure to check all errors, even from w.Write:

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type Profile struct {
	Name    string
	Hobbies []string
}

type JsonServer struct {
	code int
}

func (j *JsonServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(j.code)

	profile := Profile{"Alex", []string{"snowboarding", "programming"}}

	js, err := json.Marshal(profile)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func main() {
	http.Handle("/", &JsonServer{200})
	log.Fatal(http.ListenAndServe(":9000", nil))
}
1 Like

With my response, maybe you want a more simple version, something like this even for your json serving method:

func (j *JsonServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(j.code)

	profile := Profile{"Alex", []string{"snowboarding", "programming"}}

	if err := json.NewEncoder(w).Encode(&profile); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
1 Like

Hi @radovskyb
Will give this a try. Need to see what the issue really is. Setting twice might have created an issue? This code too sets it twice. Not sure what is the issue. Just to see if the header is written into I set the j.code for http.StatusFail to see the response in red(404) in the browser. So the traversal was not the issue. Will update here once I fix it. Thanks again…:slight_smile:

1 Like

No problem, I hope you work it out :slight_smile:

Maybe try using something like my second response as the ServeHTTP method and see if it’s cleaner for you.

Hi @radovskyb
Ya…Will check that out. Actually I am not sure which one is good when it comes to json, Marshal or Decoder…Is there any performance gains or anything between them?

Since you are writing directly to a writer I would personally use json.NewEncoder(w).Encode(...) instead of using json.Marshal(...), and only after marshalling data into JSON, writing to the writer.

My rule of thumb is that I use Encode when I’m writing directly to a writer, but use Marshal when I need to to something else with the bytes first before writing the JSON somewhere.

1 Like

Ya. Seems fair. Will try out both ways.

Let me know if you still have any issues :slight_smile: Hopefully it will work now!

Ya sure. Thanks a lot…:slight_smile:

1 Like

Just one more thing… If you are going to use a simple middleware like the JSON one I posted in my first example and you are going to encode many different types of data and serve them the same simple way, you could use something like this since it’s very clean:

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type Profile struct {
	Name    string
	Hobbies []string
}

type JsonServer struct {
	data interface{}
	code int
}

func (j *JsonServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(j.code)

	if err := json.NewEncoder(w).Encode(&j.data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func main() {
	profile := Profile{"Alex", []string{"snowboarding", "programming"}}

	http.Handle("/", &JsonServer{data: &profile, code: http.StatusOK})
	log.Fatal(http.ListenAndServe(":9000", nil))
}
2 Likes

Ya. A single framework kinda thing for all purpose. Cool

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.