I am working on a patch restful request that the body json contain some omitted value while sending to golang. Since an unset value will lead the golang struct become default value. So I would like to know if there are any solution to deal with patch request omit data?
As I know, a basic type like string / int cannot be nullable in golang. there are different approach to deal with unset value patch request. For example:
using pointer to deal with null problem
type User struct {
Name *string
}
using nullable library
type User struct {
Name sql.NullString
}
using map[string][]interface{}
to see if the value is set
Is there any better solution to deal with nullable value inside struct? since this 3 should be work around to deal with the nullable value.
Use a pointer along with the omitempty
tag. This way you can differentiate between an unset value, nil, and an intentional zero value ("", false, 0).
type User struct {
Name *string `json:"name,omitempty"`
}
Another solution is writing your own type, and implement json.Unmarshaller
package main
import (
"encoding/json"
"fmt"
)
type NullString struct {
Data string
Null bool
}
func (ns *NullString) UnmarshalJSON(d []byte) error {
if string(d) == "null" {
// this is based on your need. you may add a new field here
ns.Null = true
return nil
}
return json.Unmarshal(d, &ns.Data)
}
type Test struct {
Data1 NullString `json:"data1"`
Data2 NullString `json:"data2"`
Data3 NullString `json:"data3"`
}
const t = `{"data1":null, "data2":"string"}`
func main() {
p := Test{}
json.Unmarshal([]byte(t), &p)
fmt.Printf("%+v", p)
}
result is {Data1:{Data: Null:true} Data2:{Data:string Null:false} Data3:{Data: Null:false}}
if the value is null
then the Null field is set. also you can simply add extra fields to this struct if needed. for example a field to track if the function is called or not.
ps : also see the json.Marshaller for the reverse from struct to json.
If you're using PATCH
in a RESTful way, that means it's updating some existing data, and only overwriting those fields included in the request body. Which means you don't actually need to know which fields are set or not; you can just load your canonical object and unmarshal over it to replace any fields that are found in the JSON, while leaving any others untouched:
canonObj := getObjectFromDBOrSomething()
err := json.NewDecoder(req.Body).Decode(canonObj)
This will overwrite any fields in canonObj
with fields from the request, but any fields not in the request won't be touched.