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 a given key and its value is 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, I was asked to implement several scenarios for processing PATCH requests. Here they are:
- When a value for a key is explicitly set to
null
— setnull
value 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 a 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 there will be a 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 an attempt to set another ‘custom’ type will cause an error by the validator. For such cases in go-swagger, there is an 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 a package nullable, created by me for this case and will set type Int
from this package as a structure field in generated code. Next step is to define this definition as a reference for BlogUpdateRequest
published_at
property.
Thus BlogUpdateRequest
model will be generated with nullable.Int
type field in the structure.
With the given model, there’s an ability to decide whether to update thepublished_at
field, update it as a null value or just skip it.
The full code can be found on github.