Go: Nested Struct Marshall & UnMarshall

The journey of “struct to json” -> “json to struct”

Mapping your model object to the response JSON from an API or reading from an input file is a common scenario while building a distributed application using Go.

Let’s take an example to understand: We have a nested JSON sample response as input in our application. Input consists of an encrypted message and key. If you look closely encryption mechanism is Caesar cipher.

{
"sampleInput": {
"input": {
"encryptedMessage": "F KFRTZX JCUQTWJW TSHJ XFNI, YMFY YMJ JCYWFTWINSFWD NX NS BMFY BJ IT, STY BMT BJ FWJ. LT JCUQTWJ!",
"key": 5
}
}
}

Let us construct the model hierarchy for this input.

type input struct {
EncryptedMessage string `json:"encryptedMessage"`
Key int `json:"key"`
}
type sampleInput struct {
Input input `json:"input"`
}
type sample struct {
SampleInput sampleInput `json:"sampleInput"`
}

In this case, I am considering reading input from a local file.

Let’s UnMarshall it (using “encoding/json” module)

file, _ := ioutil.ReadFile("input-nested.json")var data sample
err := json.Unmarshal([]byte(file), &data)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(data)

The output of the print statement would look like:

{{{F KFRTZX JCUQTWJW TSHJ XFNI, YMFY YMJ JCYWFTWINSFWD NX NS BMFY BJ IT, STY BMT BJ FWJ. LT JCUQTWJ! 5}}}

Create a simple method to decrypt the encrypted message using the key.

func caserCipherDecrypt(str string, key int) string {
len := len(str)
msg := ""
str = strings.ToUpper(str)
for i := 0; i < len; i++ {
k := int(str[i])
if k < 65 {
msg = msg + string(k)
} else {
j := (int(str[i]) - key)
if j < 65 {
j = j + 26
}
msg = msg + string(j)
}
}
return msg
}

Calling the `caserCipherDecrypt` method with params from the model class which we used to unmarshal the data.

msg := caserCipherDecrypt(data.SampleInput.Input.EncryptedMessage, data.SampleInput.Input.Key)

Create an Output model to display the decrypted message

type output struct {
Message string `json:"message"`
}
type sampleOutput struct {
Output output `json:"output"`
}
type response struct {
SampleOutput sampleOutput `json:"sampleOnput"`

Marshall using the sample module. We need to provide our Output model with the decrypted message.

var resp = response{
SampleOutput: sampleOutput{
Output: output{
Message: msg,
},
},
}
outputJSON, _ := json.Marshal(resp)

Printing the output to the console would look like:

{"sampleOnput":{"output":{"message":"A FAMOUS EXPLORER ONCE SAID, THAT THE EXTRAORDINARY IS IN WHAT WE DO, NOT WHO WE ARE. GO EXPLORE!"}}}

Either construct the output value using a model hierarchy or can be constructed using a string literal.

GitHub code repo: link

Thank you for reading, give a cheer! if you like the post.

Happy Coding ❤