Handling JSON null or missing values with go-swagger
In JSON there are two ways to represent null values, first is when there is no value for given key and its value implicitly set to null, and second is when the key is present and its value is explicitly set to null.
Recently when working on tasks for building microservices with go-swagger, for a current project I’m working on, I was asked to implement several scenarios for processing PATCH requests. Here they are:
- When a value for a key is explicitly set to
nullvalue for the column at DB.
- When a value for a key is implicitly set to
null— skip the update.
- When a value for a key is a valid value for given type — set given value for the column at DB.
In Go, as you may know, If a value for a field is not defined, the language will initialize memory for it and set the value as a zero value for the given type. So if in a request will be missing key for the specified field,
json.Unmarshal will just skip it and its value will be the zero value for the type.
To handle such case, the new type should be defined with the custom behavior of how JSON gets unmarshalled by implementing the
Unmarshaler interface from
encoding/json package, more detailed about it can be read in the article How to determine if a JSON key has been set to null or not provided by Joh Calhoun.
Next step was to understand how to define those new types for properties in swagger, as you may know, OpenAPI v2 gives us 6 types and attempt to set another ‘custom’ type will cause an error by the validator. For such cases in go-swagger, there is extension
x-go-type which gives the ability to set our new type in generated models. So the creation of definition, for example,
NullableInt with the
x-go-type extension will give the ability to use it as the reference in other definitions.
The generator will import package nullable, created by me for this case and will set type
Int from this package as structure field in generated code. Next step is to define this definition as a reference for
BlogUpdateRequest model will be generated with
nullable.Int type field in the structure.
With given model, there’s ability to decide whether to update
published_at field, update it as null value or just skip it.
The full code can be found on github.