Table of Contents
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:
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