0%

Go_Learning_Fundamental_Json

Reference: blog_1, official docs

JSON Definition

JSON is the most popular standard data serialization format. This bllog is used to familar with the basic use of JSON Marshal and JSOM UnMarshal in Go. Any deep detail about json could find from above official docs.

UnMarshal JSON Data to Struct

To Struct

The Unmarshal function provided by Go standard library is used to parse raw json data []byte format to variables.

To Simple Struct

Most simple way is parse to a simple struct. For example a person object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"encoding/json"
"fmt"
)

type Person struct {
Name string
Age int
}

func main() {
rawJsonStr := `{"name": "Qingzhi", "Age": 15}`
var p Person
json.Unmarshal([]byte(rawJsonStr), &p)
fmt.Printf("After unmarshall got person %#v \n", p)
}
// After unmarshall got person main.Person{Name:"Qingzhi", Age:15}

From above example, we find that the object Person is the mirror of Raw Json DataFormat . Acturally the json umnmarshal function has a list of match standard, while that not the content today.

To Nested Struct

Nested Struct is the same usage as simple struct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"encoding/json"
"fmt"
)

type Address struct {
Country string
Province string
}

type Person struct {
Name string
Age int
Address Address
}

func main() {
rawJsonStr := `{"name": "Qingzhi", "Age": 15, "Address": {"Country": "China", "Province": "ShanDong"}}`
var p Person
json.Unmarshal([]byte(rawJsonStr), &p)
fmt.Printf("After unmarshall got person %#v \n", p)
}
// After unmarshall got person main.Person{Name:"Qingzhi", Age:15, Address:main.Address{Country:"China", Province:"ShanDong"}}

To Array

We can decode any array objectss, like below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"encoding/json"
"fmt"
)

type Address struct {
Country string
Province string
}

type Person struct {
Name string
Age int
Address Address
}

func main() {
rawJsonStr := `[
{"name": "Qingzhi", "Age": 15, "Address": {"Country": "China", "Province": "ShanDong"}},
{"name": "WuKong", "Age": 500, "Address": {"Country": "China", "Province": "ShanDong"}}
]`
var pSlice []Person
json.Unmarshal([]byte(rawJsonStr), &pSlice)
fmt.Printf("After unmarshall got person %#v \n", pSlice)
}
// After unmarshall got person []main.Person{main.Person{Name:"Qingzhi", Age:15, Address:main.Address{Country:"China", Province:"ShanDong"}}, main.Person{Name:"WuKong", Age:500, Address:main.Address{Country:"China", Province:"ShanDong"}}}

To Map

There is some scenatioies that we have no idea what kind of object would transfer to your application. In this context, use interfacr map is a good choice, after unmarshall unkown object, we can use type reflection to got the finial struct. For example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"encoding/json"
"fmt"
)

type Person struct {
Name string
Age int
}

func main() {
rawJsonStr := `{"name": "Qingzhi", "Age": 15, "Address": {"Country": "China", "Province": "ShanDong"}}`
var unkown map[string]interface{}
json.Unmarshal([]byte(rawJsonStr), &unkown)
fmt.Printf("After unmarshall got person %#v \n", unkown)
for key, value := range unkown {
fmt.Printf("key is %v, value is %v, \n", key, value)
}
}
// After unmarshall got person map[string]interface {}{"Address":map[string]interface {}{"Country":"China", "Province":"ShanDong"}, "Age":15, "name":"Qingzhi"}
// key is Address, value is map[Country:China Province:ShanDong],
/// key is name, value is Qingzhi,
/// key is Age, value is 15,

To Primitive Type

We mostly deal with complex objects or arrays when working with JSON, but data like 3, 3.1412 and "birds" are also valid JSON strings.

We can unmarshal these values to their corresponding data type in Go by using primitive types:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"encoding/json"
"fmt"
)

func main() {
numberJson := "3"
floatJson := "3.1412"
stringJson := `"bird"`

var n int
var pi float64
var str string

json.Unmarshal([]byte(numberJson), &n)
fmt.Println(n)

json.Unmarshal([]byte(floatJson), &pi)
fmt.Println(pi)

json.Unmarshal([]byte(stringJson), &str)
fmt.Println(str)
}
// 3
// 3.1412
// bird

Marshal Struct to JSON Data

The same rule could used to encode struct to json data.

From Struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"encoding/json"
"fmt"
)

type Person struct {
Name string
Age int
}

func main() {
p := Person{
Name: "Qingzhi",
Age: 15,
}
bs, _ := json.Marshal(p)
fmt.Printf("Got marshall result %v \n", string(bs))
}
// Got marshall result {"Name":"Qingzhi","Age":15}

Other tips is omited.

Practice

There is some useful api we used in our project.

Transfer object to object

Parse Struct to String

Parse String to Struct

Conclusion

As a general rule of thumb, if you can use structs to represent your JSON data, you should use them. The only good reason to use maps would be if it were not possible to use structs due to the uncertain nature of the keys or values in the data.

If we use maps, we will either need each of the keys to have the same data type, or use a generic type and convert it later.