What is a good json builder?

Many of my responses to the client include json strings, but apparently json.Marshal can raise an error and that would be terrible, is there any alternative to build a json safely?

My structs only have fields of these 3 types [bool, string, int], my question now is is there any chance that json.Marshal raises an error with those 3 types? if so what would that scenario be?

Or what limits can I put on my structs so that json.Marshal never returns an error?

Hi! If you’re talking about strictly typing, yes is possible in particular on int (which int are you using? An example of error please). However if you have to use json a lot, prefer the use json.Encoder, for better performance and customization. Usually the more precise is your struct, the less error you will get :slight_smile:

json.Encoder how to use that? Can you please give me an example? ah and I don’t have any example of error but Go documentation says that the possibility exists and I can’t risk it because if a client request is valid and it only remains to send a json string but Marshal fails it wouldn’t make any sense for the user.

The chance of json.Marshal returning an error is extremely low. I haven’t seen it in “the wild” yet. From the docs here’s one possible error:

Floating point, integer, and Number values encode as JSON numbers. NaN and +/-Inf values will return an UnsupportedValueError.

So you could create an error using a contrived example like so:

testValue := math.NaN()
m, err := json.Marshal(testValue)
if err != nil {
	fmt.Println("error:", err)
}
fmt.Println(string(m))

But I don’t know of any errors that can occur off the top of my head for int, string, or bool values. If something extreme happened and an error occurred, I would contend that the most sensible thing to do would probably be to return an internal server error to the user (and probably log the error somewhere so you can detect them without users complaining).

To answer your question about json.Encoder, assuming you are using this in an HTTP handler, you can use it like this:

http.HandleFunc("/myRoute", func(w http.ResponseWriter, r *http.Request) {
	// Contrived struct to send
	data := someStruct{}
	// Be sure to set content type
	w.Header().Set("Content-Type", "application/json")
	// Use an encoder to encode and send directly to the http.ResponseWriter.
	err := json.NewEncoder(w).Encode(data)
	if err != nil {
		// Do something
	}
})

As you can see, NewEncoder takes an io.Writer as its’ argument and when you call Encode, it writes to that writer.

1 Like

Hello, You can safely use json.Marshal for structs with fields of type bool, string, and int. In this scenario, there’s virtually no risk of json.Marshal raising an error.

To ensure that json.Marshal never returns an error for your structs, you can follow these guidelines:

Ensure Field Types: As you’ve mentioned, restrict your struct fields to only bool, string, and int types. This way, you eliminate the possibility of incompatible data types causing errors during serialization.

Handle Special Cases: While your current field types are generally safe, be cautious when dealing with int values that might overflow or string values that contain unescaped characters. Ensure your data conforms to JSON’s conventions.

Proper Struct Tags: Add struct tags (json:“fieldname”) to your struct fields to specify custom JSON field names if needed. This allows you to control the JSON key names independently of the struct field names.

I hope this will help you.

Regards
Emma Wilson

1 Like

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