The jsontype package provides some basic types for handling JSON unmarshaling in scenarios where fields may be null or absent, such as when processing data from PATCH requests. The types are inspired by the sql.Null* types from the database/sql package.
The types provided by this package are designed to work seamlessly with the encoding/json package from the Go standard library. They implement the json.Unmarshaler and json.Marshaler interfaces, making it easy to manage fields that can either be present or absent, and may or may not contain null values.
Each type includes two key fields:
Valid: Indicates whether the field contains a non-null value.Present: Indicates whether the field was included in the JSON input.
Note: When marshaling to JSON, these types do not fully support the omitempty tag. If a field's Present field is false, the field will still be included in the output JSON with a null value.
Have a for example at the following code:
package main
import (
"encoding/json"
"fmt"
"github.com/mbe81/jsontype"
)
type Person struct {
FirstName jsontype.NullString `json:"firstName"`
LastName jsontype.NullString `json:"lastName"`
City jsontype.NullString `json:"city"`
Age jsontype.NullInt `json:"age"`
}
func main() {
var p Person
err := json.Unmarshal([]byte(`{"firstName": "John", "lastName": null, "city": "New York"}`), &p)
if err != nil {
panic(err) // This example must not fail
}
fmt.Println(p)
}Running this code will print the following output:
{{John true true} { false true} {New York true true} {0 false false}}
Which corresponds to the values in the following table:
| Field | Value | Valid | Present |
|---|---|---|---|
| FirstName | "John" |
true | true |
| LastName | "" |
false | true |
| City | "New York" |
true | true |
| Age | 0 |
false | false |
Based on this you can say the following:
lastNameisnullin the JSON becauseLastName.Validis false andLastName.Presentis true.ageis absent in the JSON becauseAge.Presentis false.
You could do the same with the generic jsontype.Null[any] type, which can be used for any type:
package main
import (
"encoding/json"
"fmt"
"github.com/mbe81/jsontype"
)
type Person struct {
FirstName jsontype.Null[string] `json:"firstName"`
LastName jsontype.Null[string] `json:"lastName"`
City jsontype.Null[string] `json:"city"`
Age jsontype.Null[int] `json:"age"`
}
func main() {
var p Person
err := json.Unmarshal([]byte(`{"firstName": "John", "lastName": null, "city": "New York"}`), &p)
if err != nil {
panic(err) // This example must not fail
}
fmt.Println(p)
}Currently the following types are supported:
jsontype.NullStringjsontype.NullIntjsontype.NullFloat64jsontype.NullBooljsontype.NullTimejsontype.Null[any]
This package is released under the MIT license. See the LICENSE file for more information. Feel free to use the package as is or copy the types for use in your own projects.
Contributions are welcome! Please feel free to submit a pull request if you find any issues or would like to suggest improvements, for example by adding support for additional types.