Welcome To Golang By Example

Conversion between struct and JSON in Go (Golang)

Overview

encoding/json package provides utilities that can be used to convert to and from JSON. The same utility can be used to convert a golang struct to a JSON string and vice versa.  Two functions which are used are

Before we see how to convert a struct to JSON and vice versa we need to know two things about golang struct:

type employee struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

Notice meta tags associated with each of the fields annotated with name as ‘json’. These meta fields are used while converting a struct into JSON and vice versa.

So the above struct when converted to JSON will be as below

{
  "name" : "John",
  "age"  : 21
}

Then name key of the above JSON string will map to the Name field of the employee struct and the age key in the JSON string will map to the Age field of the struct. Also, when converting the above JSON string  to a struct, the value in the name field of json will go to value in the Name field of the struct, and value in the age field of json will go to value in the Age field of struct .

As another example, let’s say we have below struct

type employee struct {
	Name string `json:"n"`
	Age  int    `json:"ag"`
}

Then after conversion to JSON,  ‘n’ key of the JSON will map to the Name field of the struct and ‘ag’ key of the JSON will map to the Age field of the struct. So it will produce below JSON

{
  "n" : "John",
  "age"  : 21
}

Also, when converting the above JSON string  to a struct, the value in the ‘n’ field of JSON string will go to value in the Name field of the struct, and value in the ‘a’ field of json will go to value in the Age field of struct 

If the struct doesn’t contain any meta tags then the resulting key name in the JSON will be the same as the struct field’s name and vice versa. For eg if we have below struct

type employee struct {
	Name string 
	Age  int   
}

Notice then none of the fields has the JSON meta tags. So after converting to JSON it will be like

{
  "Name" : "John",
  "Age"  : 21
}

Struct to JSON

json.Marshal function can be used to convert a struct to JSON. Let’s see an example of conversion from a struct to JSON. To illustrate all points above we have created two structs

Also, the salary field in both the struct is unexported

package main
import (
    "encoding/json"
    "fmt"
    "log"
)
type employee1 struct {
    Name   string `json:"n"`
    Age    int    `json:"a"`
    salary int    `json:"s"`
}
type employee2 struct {
    Name   string
    Age    int
    salary int
}
func main() {
    e1 := employee1{
        Name:   "John",
        Age:    21,
        salary: 1000,
    }
    j, err := json.Marshal(e1)
    if err != nil {
        log.Fatalf("Error occured during marshaling. Error: %s", err.Error())
    }
    fmt.Printf("employee1 JSON: %s\n", string(j))
    e2 := employee2{
        Name:   "John",
        Age:    21,
        salary: 1000,
    }
    j, err = json.Marshal(e2)
    if err != nil {
        log.Fatalf("Error occured during marshaling. Error: %s", err.Error())
    }
    fmt.Printf("\nemployee2 JSON: %s\n", string(j))
}

Output

employee1 JSON: {"n":"John","a":21}

employee2 JSON: {"Name":"John","Age":21}

Notice that we are using json.Marshal function to convert from the struct to JSON.

For the employee1 struct to JSON conversion, the output is

{"n":"John","a":21}

This is because

For the employee2 struct to JSON conversion, the output is

{"Name":"John","Age":21}

This is because

JSON to struct

json.Unmarshal function can be used to convert from JSON to a struct. Whatever rules we discussed above also apply to conversion from JSON to a struct.  Let’s see an example

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type employee1 struct {
	Name   string `json:"n"`
	Age    int    `json:"a"`
	salary int    `json:"s"`
}

type employee2 struct {
	Name   string
	Age    int
	salary int
}

func main() {
	e1Json := `{"n":"John","a":21}`

	var e1Converted employee1
	err := json.Unmarshal([]byte(e1Json), &e1Converted)
	if err != nil {
		log.Fatalf("Error occured during unmarshaling. Error: %s", err.Error())
	}
	fmt.Printf("employee1 Struct: %#v\n", e1Converted)

	e2Json := `{"Name":"John","Age":21}`
	var e2Converted employee2
	err = json.Unmarshal([]byte(e2Json), &e2Converted)
	if err != nil {
		log.Fatalf("Error occured during unmarshaling. Error: %s", err.Error())
	}
	fmt.Printf("\nemployee2 Struct: %#v\n", e2Converted)
}

Output

employee1 Struct: main.employee1{Name:"John", Age:21, salary:0}

employee2 Struct: main.employee2{Name:"John", Age:21, salary:0}

This example uses the json string that was the output from the first example. Here we are using the json.Unmarshal function to convert from JSON string to structThe first thing to note is that we need to pass the address of the struct to the json.Unmarshal function as below

err = json.Unmarshal(j, &e1Converted)

The first argument is the JSON bytes and the second is the address of the struct.

Unmarshing of

{"n":"John","a":21}

into employee1 struct outputs

main.employee1{Name:"John", Age:21, salary:0}

Unmarshling of

{"Name":"John","Age":21}

into employee2 struct outputs

main.employee2{Name:"John", Age:21, salary:0}

Also if you try unmarshalling

{"n":"John","a":21}
 into employee2 struct then the output will be 
main.employee2{Name:"", Age:0, salary:0}

Nothing will get unmarshalled because there are no meta tags in the employee2 struct and key names in the employee2 struct and key names in JSON is different. Hence an empty employee2 struct will be created with each of the fields in the struct initialized with the default zero value of its type.

What if the JSON string contains the salary field. Then the value for the salary field in the JSON string will not reflect in the salary field of the struct because the salary field is not exported in the struct. See this example for the same.

package main
import (
    "encoding/json"
    "fmt"
    "log"
)
type employee1 struct {
    Name   string `json:"n"`
    Age    int    `json:"a"`
    salary int    `json:"s"`
}
func main() {
    e1Json := `{"n":"John","a":21,"salary":1000}`
    var e1Converted employee1
    err := json.Unmarshal([]byte(e1Json), &e1Converted)
    if err != nil {
        log.Fatalf("Error occured during unmarshaling. Error: %s", err.Error())
    }
    fmt.Printf("employee1 Struct: %#v\n", e1Converted)
}

Output

employee1 Struct: main.employee1{Name:"John", Age:21, salary:0}

Even though the salary field in the JSON string has a value of 1000 but after converting it to the struct the salary field in the struct is 0.