Since empty string is the zero/default value for Go string, I decided to define all such fields as interface{} instead. for example
Another way actually is a workaround with using the MarhshalJSON and UnmarshalJSON interface method offered by the json lib of golang. The code is as below:
type MyType string
type MyStruct struct {
A MyType `json:"my_type"`
}
func (c MyType) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
if len(string(c)) == 0 {
buf.WriteString(`null`)
} else {
buf.WriteString(`"` + string(c) + `"`) // add double quation mark as json format required
}
return buf.Bytes(), nil
}
func (c *MyType)UnmarshalJSON(in []byte) error {
str := string(in)
if str == `null` {
*c = ""
return nil
}
res := MyType(str)
if len(res) >= 2 {
res = res[1:len(res)-1] // remove the wrapped qutation
}
*c = res
return nil
}
then when using json.Marshal, the MyType value will be marshaled as null.
Can be used https://github.com/guregu/null
type student struct {
FirstName null.String `json:"first_name"`
MiddleName null.String `json:"middle_name"`
LastName null.String `json:"last_name"`}
You could use something like sql.NullString,use 'Valid' to check if it is a nil value.
NullString represents a string that may be null. NullString implements the Scanner interface so it can be used as a scan destination:
type NullString struct {
String string
Valid bool // Valid is true if String is not NULL
}
var s NullString
err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
...
if s.Valid {
// use s.String
} else {
// NULL value
}
Please DO NOT use pointers like below:
type student struct {
FirstName *string `json:"first_name"`
MiddleName *string `json:"middle_name"`
LastName *string `json:"last_name"`
}
Because you need check nil value and dereference like below everywhere,and maybe cause unexpected crash somewhere:
if obj.FirstName != nil {
fmt.Print("%s", *obj.FirstName)
}
I have compared two solution and choosed former method in my extensively production code,it work ok.
In json package documentation :
Pointer values encode as the value pointed to. A nil pointer encodes as the null JSON object.
So you can store a pointer to a string which will be encoded as a string if not nil and will be encoded as "null" if nil
type student struct {
FirstName *string `json:"first_name"`
MiddleName *string `json:"middle_name"`
LastName *string `json:"last_name"`
}
For the case of a json object with null strings, its easiest to use the omitempty decorator on the field.
type student struct {
FirstName string `json:"first_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
LastName string `json:"last_name"`
}
With the above declaration, only if first_name was assigned will that key show up in the resultant json. last_name, on the otherhand, will always show up in the result with a value of "" if not assigned.
Now when you start including numeric fields where 0 could be a value, using omitempty doesn't do what one would expect. A 0 value always drops the field, and we need to be able to differentiate between a 0 value and an unassigned value. Here use of library such as https://github.com/guregu/null may be advisable.
More discussion here: https://www.sohamkamani.com/blog/golang/2018-07-19-golang-omitempty/