Json serialization of optional fields in Go

A quick guide to omitempty, default values and nil

Emre Tanriverdi
5 min readApr 25, 2021

Go is widely being used for backend programming and its community is growing larger each day. Personally I love coding in Go.

Lately I was working on a project that has optional fields in its datasource and needed to manipulate the response based on business needs.
I thought it’d be a good idea to make a small tutorial about it.

Let’s create a simple struct and see the response:

Commented out lines indicate the values in datasource.

Don’t hate me for using uint64 for childrenCount, it’s just an example. :)

We are deserializing the entity from our datasource before serializing it.
The corresponding response is:

Json response from an example GET request -> /employees/1

Let’s put an alias for it to use in json serializing/deserializing.

Commented out lines indicate the values in datasource.

And the response will be:

JSON response from an example GET request -> /employees/1

To serialize nonexistent values with its defaults

The default approach sets default values for optional/nonexistent fields.

Commented out lines indicate the values in datasource.
JSON response from an example GET request -> /employees/1

Do you see what could cause a problem here?

In my datasource I have an optional field called childrenCount, which holds the number of kids each employee have. For one employee it’s 0 and for another employee it’s null. I wouldn’t want to show 0 for both fields,
because having 0 and not having information is two different things.

If you can’t ever have 0 in your datasource, you can safely behave 0 as if it’s null. It’s great! You can stop here.

But now for this case, I need to differentiate between 0 and null.

To serialize both nonexistent and “empty” values

This approach omits both null and empty values. (such as 0, empty string).

Go has an omitempty tag that helps us to not serialize empty fields.

Let’s add ownedCars field to our entity and implement it.

Commented out lines indicate the values in datasource.
JSON response from an example GET request -> /employees/1

Response didn’t change because ownedCars is not empty.

So let’s say it’s null for ownedCars.

Commented out lines indicate the values in datasource.

And the response is now:

JSON response from an example GET request -> /employees/1

It didn’t serialize the empty value, yay!

But remember childrenCount was also optional, so let’s put omitempty to it and let’s say this time we have Julia with us and she has no kids.

Commented out lines indicate the values in datasource.
JSON response from an example GET request -> /employees/2

Now both childrenCount and ownedCars is omitted in response, since Go reads 0 as an empty value.

If it’s okay for your business requirement, it’s great! You can stop here.
But now for this case, I lost the childrenCount value, even though I know it’s 0 in the datasource as a valid value for this case.

To not serialize nonexistent fields, but serialize “empty” fields

This approach omits null values and leaves zeros and empty strings as it is.

So this was our latest struct:

(Let’s say goodbye to Jason and continue with Julia.)

Commented out lines indicate the values in datasource.

The main reason for Go to assign default values to these fields is because types such as uint64 or string can not be nil (for instance, slices can be nil), but their pointers can. So we must hold a pointer reference in our entity.

Such as:

Commented out lines indicate the values in datasource.

And now the response will be:

JSON response from an example GET request -> /employees/2

Now it works as expected!

If you’d like to convert this entity to another struct, such as EmployeeDto,
you can again hold a pointer reference and set the fields directly, it’ll work.

If it’s okay for your business requirement, it’s great! You can stop here.
(For me, this was exactly what I wanted.)

But as you may have realized, this approach doesn’t serialize null fields.
If you need to explicitly serialize null fields as null in response, let’s continue.

To serialize nonexistent fields as null

This approach serializes null values as null and leaves “empty” fields as it is.

To this day, I haven’t yet needed to explicitly serialize null fields, just omitting them from response was enough for the client part to see it as null.

But if you need to use it that way, there is a library called guregu/null that is widely used by Go community.

I personally didn’t use it in production, but it should be fine.

Its usage is very easy:

Commented out lines indicate the values in datasource.

And now the response will be:

JSON response from an example GET request -> /employees/2

Ta-da!

I wanted to show a quick guide on how to manipulate json’s serialization method according to our needs, as I struggled to find a guide that shows different behaviors step-by-step.

All feedbacks are welcome and I hope it was helpful. :)

Thank you for reading! ❤️

--

--