Photo by Chinmay B on Unsplash
Working with Golang can be a pain sometimes, especially when you are new and don’t yet appreciate its beauty. A trivial task like processing a JSON response object - which is way easier in JS, to a point where you don’t even have to care about using variables to hold those values - in Golang, becomes too complicated.
But trusting the process and the wise words spoken around, if you be patient and just continue with the tedious process, there will come a point where you would love doing it in Golang. In this post, I help relieve some of that pain.
What’s the deal with JSON and Golang?
JSONs are the top-most universal standards defined for communication of text based information across tools, interfaces, and SaaS-based services. It enjoys inherent support in all the major programming languages today - arguably except Golang.
This caused headaches for me for a few weeks, until the requirements forced it down my throat - a hard pill to swallow. Especially, coming from a JS background, I found it absolutely useless to do so much of wiring just to process a simple JSON - forget about the nested ones.
How we do it in JS?
Its a joke - and I say this with a sense of appreciation. It is way too easy to access attributes or loop over a JSON object for processing. Let us consider a simple JSON object that looks like below.
{
"name": "value",
"env" : "production"
}
We can simply access name and env values by doing this:
var jsonObj = <object above>
console.log(jsonObj.name)
console.log(jsonObj.env)
This saves up a lot of development time.
In Golang…
Like otherwise, even in Golang you need to know the structure of the JSON object before running the executable. We take advantage of this to explicitly define a struct for the JSON object being processed. Golang is a bit orthodox that way. To process the JSON object above, we first define a struct as below.
type JSONObj struct {
Name string `json:"name"`
Env string `json:"env"`
}
The code block above just defines the struct in Golang to process the corresponding instance of JSON object. As we can see, we explicitly define the type (as string) for each of the attributes which would be processed by the functions. Additionally, json:”name”
and json:”env”
tells the compiler that the incoming JSON object would have attributes named (keys) with these values.
Further, to actually access these values the incoming JSON object - let us call it a response - has to be Unmarshalled
into this struct, and vice versa - Marshalled
to be converted back in byte format if it has to be returned. To do the same, we have to use the json
module of Golang as shown below.
// Assuming we get this response in response.Body
response, err := ioutil.ReadAll(response.Body)
var jsonResp JSONObj
err := json.Unmarshall(response, &jsonResp)
// Access the attributes now -
fmt.println(jsonResp.name, jsonResp.env)
It seems like there is a lot going on here. But as I said before, trust the process. It is this strongly typed nature of Golang which makes it way more performant than JS.
Think of this like an essential transformation of the incoming JSON object so that it can be processed normally in the Golang environment. For the specific understanding of the Golang syntax above, if you are not familiar, I suggest you to check out the documentation or simply ChatGPT it. ;)
What about complex JSONs?
Yes, you guessed it right - things get even worse in Golang. In cases where we have multi-nested JSON objects and for the sake of keeping the code readable, we make use of multiple structs. Consider nested JSON example below.
{
"name": "John Doe",
"age": 30,
"contact": {
"email": "john@example.com",
"phone": "123-456-7890"
},
"address": {
"street": "123 Main St",
"city": "New York",
"zipcode": "10001",
"country": "USA"
}
}
To consume and process such a JSON response, the structs below have to be created, before we can Unmarshall
or Marshall
the same.
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Contact Contact `json:"contact"`
Address Address `json:"address"`
}
type Contact struct {
Email string `json:"email"`
Phone string `json:"phone"`
}
type Address struct {
Street string `json:"street"`
City string `json:"city"`
Zipcode string `json:"zipcode"`
Country string `json:"country"`
}
Notice how the structs for nested JSONs - Address
and Contact
- are created, and then used in the “parent” struct named Person
. Similar pattern is followed if we have 3-level, 4-level, so-on-and-so-forth level of nested JSON.
What have you decided?
Before we talk about the ChatGPT part, perhaps you are thinking this to yourself if you are not a Golang dev already. Not that ChatGPT should be the reason for you to choose this language. Golang has its merits which far outweigh than this generic trick.
Looking at the difference above - would you be interested in learning Golang or stick to what you have been doing?
No doubt, writing Golang code is tedious. But if you ask any cloud architect worried about compute costs - they will any day prefer Golang.
ChatGPT? Relieve pain?
Now straight to the point - since we already know what kind of JSON is going to be processed, we can simply ask ChatGPT to generate the corresponding structs and it does so in seconds - perfectly with the json:”<attribute_name>”
notations.
I am shameless in saying this because:
We cannot ignore the reality of ChatGPT. When space travel has become affordable, why would you still buy vacations in Hawaii?
Manually typing structs is really a tedious and slow process, prone to human error - thus slowing down the development.
That was the tip with some insight and background in Golang. I highly encourage all the web devs to learn Golang for all the right reasons. By no way I meant other languages are not good, each language has its merits.
Sumeet N.
Top comments (0)