Introduction
Parsing and storing data in JSON(JavaScript Object Notation) format has gained popularity due to its ease of use, representation of data in key-value pairs, and language independence. In this blog, we will explore how we can easily parse a JSON file using a "struct" in Go.
JSON example
In the following example, user data is represented as JSON, including various data types such as string, int, float, boolean, slice, and map.
{
"userId": 1,
"userName": "Alex",
"isActive": true,
"skills": {
"languagesKnown": [
"Python",
"Go"
],
"passion": [
"Technical Program Management",
"Automation"
]
},
"roles": [
"project-lead",
"billing-admin"
],
"training-credit": 500.5
}
Steps to parse the JSON
We need to follow these steps to parse the JSON using a struct:
Define a struct for the keys in JSON
Read the JSON file
Unmarshal the JSON using the Go standard library
Access values from the struct variable.
1. Define a struct for the keys in JSON
"struct" is a powerful data type in Go that allows consolidating data from different data types into one single variable.
To parse the above JSON, we will need the following two structs.
All the keys from the JSON can be directly represented in the struct, except for the "skills" key, which has nested keys - "languageKnown" and "passion".
As a result, we need an additional struct for "skills", as shown below.
type SkillSet struct {
LanguagesKnown []string
Passion []string
}
We have the following struct for the entire JSON, including the above SkillSet struct.
type UserData struct {
UserId int
UserName string
IsActive bool
Roles []string
TrainingCredit float32 `json:"training-credit"` // since json file has different key(training-credit), hence we map to TrainingCredit
Skills SkillSet
}
With the UserData struct provided above, we have successfully mapped all the keys in the JSON to their corresponding data types.
We can now create a variable of type "UserData" using the below code:
var userInfo UserData
2. Read JSON file
We can read the JSON file using os.ReadFile() from the standard Go library. ReadFile() function returns a byte slice of the JSON file content and an error in case of issues when reading a file.
fileByte, err := os.ReadFile("jsonParsing/hr_data.json")
Refer https://pkg.go.dev/os#ReadFile for more details on os.ReadFile() function.
3. Unmarshalling
Unmarshalling is the process of converting external data (in our case, a byte slice of the JSON file) into a Go object (in our case, a struct).
Marshaling, on the other hand, is the process of converting Go objects into JSON format so that they can be read externally.
In Go, we can unmarshal using the standard Go library - json.Unmarshal(). This function takes a byte slice and a pointer variable to store the JSON data, as shown below:
err = json.Unmarshal(fileByte, &userInfo)
When there are no errors, all JSON data will be transferred to the userInfo variable.
Refer https://pkg.go.dev/encoding/json#Unmarshal for more details on json.Unmarshal() function.
4. Access values from the struct variable
After unmarshalling, values can be retrieved using userInfo.{key} as shown below:
fmt.Printf("------Employee Details: %s------\n", userInfo.UserName)
fmt.Println("User ID:", userInfo.UserId)
fmt.Println("Is Active:", userInfo.IsActive)
fmt.Println("Available training credit", userInfo.TrainingCredit)
fmt.Println("Languages known:", userInfo.Skills.LanguagesKnown)
fmt.Println("Passionate about:", userInfo.Skills.Passion)
So far, we have explored parsing JSON with a single record. By making a few changes to the above code, we could parse more records.
JSON example with multiple records
Here is a JSON file with multiple records.
[
{
"userId": 1,
"userName": "Alex",
"isActive": true,
"skills": {
"languagesKnown": [
"Python",
"Go"
],
"passion": [
"Technical Program Management",
"Automation"
]
},
"roles": [
"project-lead",
"billing-admin"
],
"training-credit": 500.5
},
{
"userId": 2,
"userName": "Tim",
"isActive": true,
"skills": {
"languagesKnown": [
"JAVA",
"Node.js"
],
"passion": [
"Web Development",
"DevOps"
]
},
"roles": [
"project-member",
"billing-viewer"
],
"training-credit": 98.5
},
{
"userId": 3,
"userName": "Ram",
"isActive": true,
"skills": {
"languagesKnown": [
"Python",
"ABAP"
],
"passion": [
"Web Services",
"CI/CD Pipelines"
]
},
"roles": [
"project-admin",
"billing-viewer"
],
"training-credit": 44.5
},
{
"userId": 4,
"userName": "Sam",
"isActive": true,
"skills": {
"languagesKnown": [
"Go"
],
"passion": [
"DevOps"
]
},
"roles": [
"project-member"
],
"training-credit": 128.5
}
]
Let's create a slice variable of type "UserData" using the following code to accommodate more records.
var userInfo []UserData
We can use for loop to iterate over the records. Here is the code snippet:
package main
import (
"encoding/json"
"fmt"
"os"
)
type SkillSet struct {
LanguagesKnown []string
Passion []string
}
type UserData struct {
UserId int
UserName string
IsActive bool
Roles []string
TrainingCredit float32 `json:"training-credit"` // json file contains different key(training-credit), hence we map to TrainingCredit
Skills SkillSet
}
func main() {
var userInfo []UserData
fileByte, err := os.ReadFile("jsonParsing/hr_data.json")
if err != nil {
fmt.Printf("Error occured while reading hr json. Err:%s", err)
}
err = json.Unmarshal(fileByte, &userInfo)
if err != nil {
fmt.Printf("Error occured while unmarshalling hr json. Err:%s", err)
}
// for loop to iterate over the records
for _, value := range userInfo {
fmt.Printf("------Employee Details: %s------\n", value.UserName)
fmt.Println("User ID:", value.UserId)
fmt.Println("Is Active:", value.IsActive)
fmt.Println("Available training credit", value.TrainingCredit)
fmt.Println("Languages known:", value.Skills.LanguagesKnown)
fmt.Println("Passionate about:", value.Skills.Passion)
}
}
This blog provides an example of how to parse a JSON file using a struct in Go. It explains how to define a struct, read the JSON file, unmarshal it, and access values from the struct variable. It also provides an example of a JSON file with multiple records and a for loop to iterate over the records, printing out the user details.