Writing custom JSON marshalling

Sometimes a type doesn’t have an obvious mapping to JSON.

How would you serialize time.Time? There are so many possibilities.

Go provides a default JSON mapping for time.Time. We can implement custom marshaller for user-defined types like structs.

For existing types we can define a new (but compatible) type.

Here’s a custom marshalling and unmarshaling for time.Time that only serializes year/month/date part:

https://codeeval.dev/gist/686e8b7952bf3a78c3dd27fe2b759f36

Notice that receiver type of UnmashalJSON is a pointer to the type.

This is necessary for changes to persist outside the function itself.

Marshaling structs with private fields

Consider a struct with both exported and unexported fields:

type MyStruct struct {
    uuid string
    Name string
}

Imagine you want to Marshal() this struct into valid JSON for storage in something like etcd.

However, since uuid in not exported, the json.Marshal() skips it.

To marshal private fields without making them public we can use a custom marshaller:

https://codeeval.dev/gist/9dc69d886e9faf8db3d8315decb3d075

Custom marshaling behind the scenes

How does custom marshaling works?

Package JSON defines 2 interfaces: Marshaler and Unmarshaler.

type Marshaler interface {
    MarshalJSON() ([]byte, error)
}

type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}