Golang JSON Omitempty Usage [SOLVED]


Written By - Tuan Nguyen
Advertisement

When trying to encode a struct to JSON if you've used Go for a while, you've undoubtedly run into the omitempty tag. This post will clarify the meaning of the omitempty tag, as well as several typical difficulties and workarounds.

 

Basic example of using golang JSON omitempty

There will ultimately be a requirement to encode some data as JSON when using Go to create web applications or HTTP servers.

One significant distinction is that there are always explicitly specified fields in structs, whereas there aren't any in JSON. Take this Go example of describing a person as a struct:

type Person struct {
	Id int
	Name string
	PhoneNumber string
}

Here is an example of encoding a person to JSON, and print out the result:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Id          int
	Name        string
	PhoneNumber string
}

func main() {
	per := Person{
		Id:          1,
		Name:        "Harry Potter",
		PhoneNumber: "+198562478",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Id":1,"Name":"Harry Potter","PhoneNumber":"+198562478"}

If the person do not have PhoneNumber, the output will be:

func main() {
	per := Person{
		Id:   2,
		Name: "Ron Potter",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Id":2,"Name":"Ron Potter","PhoneNumber":""}

We can do it better by using omitempty tag. Let’s add the omitempty tag to our Person struct:

Advertisement
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Id          int
	Name        string
	PhoneNumber string `json:",omitempty"`
}

func main() {
	per := Person{
		Id:   2,
		Name: "Ron Potter",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Id":2,"Name":"Ron Potter"}

 

Using Golang Omitempty with nested struct

If we have nested struct, even when we use omitempty tag, that field will automatically constructed with empty value. Here is an example of using omitempty tag with a nested struct:

package main

import (
	"encoding/json"
	"fmt"
)

type PhoneNumber struct {
	CallingCode string
	Number      string
}
type Person struct {
	Id          int
	Name        string
	PhoneNumber PhoneNumber `json:",omitempty"`
}

func main() {
	per := Person{
		Id:   2,
		Name: "Ron Potter",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Id":2,"Name":"Ron Potter","PhoneNumber":{"CallingCode":"","Number":""}}

This is because structs do not have any empty value in Go. To solve this, use a struct pointer instead. Despite the fact that structs do not contain a "empty" value, struct pointers do, with nil serving as the empty value.

package main

import (
	"encoding/json"
	"fmt"
)

type PhoneNumber struct {
	CallingCode string
	Number      string
}
type Person struct {
	Id          int
	Name        string
	PhoneNumber *PhoneNumber `json:",omitempty"`
}

func main() {
	per := Person{
		Id:   2,
		Name: "Ron Potter",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Id":2,"Name":"Ron Potter"}

 

0 (Zero), “” and nil value in Golang

For better understand omitempty tag, you must know the differences among a default value, and a zero value. Consider the below example where Person with id 0:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Id          int `json:",omitempty"`
	Name        string
	PhoneNumber string
}

func main() {
	per := Person{
		Id:          0,
		Name:        "Anna Potter",
		PhoneNumber: "+1385698",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))
}

Output:

{"Name":"Anna Potter","PhoneNumber":"+1385698"}

We would like to include this information in the JSON object even if the person's id in this situation may actually be 0. At the same time, we would like the key to be omitted if the id is not specified. In other words, we do not want 0 to be the “empty” value for id.  One way to solve this is to use an int pointer. Now the empty value is a nil pointer, which is different from the value of 0:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Id          *int `json:",omitempty"`
	Name        string
	PhoneNumber string
}

func main() {
	idPer := 0
	per := Person{
		Id:          &idPer,
		Name:        "Anna Potter",
		PhoneNumber: "+1385698",
	}

	per2 := Person{
		Name:        "Luna Wood",
		PhoneNumber: "+478564",
	}

	byteJson, _ := json.Marshal(per)
	fmt.Println(string(byteJson))

	byteJson2, _ := json.Marshal(per2)
	fmt.Println(string(byteJson2))
}

Output:

{"Id":0,"Name":"Anna Potter","PhoneNumber":"+1385698"}
{"Name":"Luna Wood","PhoneNumber":"+478564"}

 

Summary

Although we have discussed how to utilize omitempty tag, the most crucial thing to keep in mind is that it should only be used sometimes. There is really no purpose to use the omitempty tag in the first place if the application consuming the JSON objects produced by the Go program doesn't distinguish between undefined keys and zero value keys. If you do decide to use it, be sure that your application and Go's meaning of "empty" are compatible.

If a field should be ignored when marshaling or unmarshaling, use a dash (-) for the name. If the field should be left out of the output when it is empty, add ,omitempty after the name.

 

References

https://en.wikipedia.org/wiki/JSON
https://go.dev/tour/basics/12

 

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment