There was a recent experience when I was playing around with Go-lang’s struct and JSON marshal. Take a look at below example
package main
import (
"fmt"
"encoding/json"
)
type Trip struct {
tripId string
tripType string
}
func main() {
trip := Trip{tripType: "air"}
fmt.Println(trip)
tripJson, err := json.Marshal(trip)
fmt.Println(err)
fmt.Println(string(tripJson))
}
Below is output
{ air}
<nil>
{}
Did you notice the above code? Within the same package printing trip
returns the data ({ air}
) correctly but tripJson
returns empty ({}
) with no error. It’s because the json
package will silently ignore private fields in your struct.
Any method or variables starting with a small case letter will be considered as private / Unexported fields. That’s not how “privacy” works in Go
In the above case, json
is a separate package, so the json
package will not have access for setting/getting private / Unexported fields.
package main
import (
"fmt"
"encoding/json"
)
type Trip struct {
TripId string
TripType string
}
func main() {
trip := Trip{TripType: "air"}
tripJson, _ := json.Marshal(trip)
fmt.Println(string(tripJson))
}
Below is output
{"TripId":"","TripType":"air"}
package main
import (
"fmt"
"encoding/json"
)
type Trip struct {
tripId string `json:"trip_id"`
tripType string `json:"trip_type"`
}
func main() {
trip := Trip{tripType: "air"}
fmt.Println(trip)
tripJson, err := json.Marshal(trip)
fmt.Println(err)
fmt.Println(string(tripJson))
}
With the above code, go vet
will throw warnings for using exported fields when it is tagged with a json tag.
➜go vet trip/trip.go
trip/trip.go:9:4: struct field tripId has json tag but is not exported
trip/trip.go:10:4: struct field tripType has json tag but is not exported
It’s always safe to use json tags even when keys are the same, this helps to avoid mistakes to some extent. When invoking vet
would show warnings when you are using private variables with json
tag.
Note: Go compiler still will not throw error for above scenario.
➜go run trip/trip.go
{ air}
<nil>
{}