如何在Golang中处理具有未设置值的补丁请求

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:

  1. using pointer to deal with null problem

    type User struct {
        Name *string
    }
    
  2. using nullable library

    type User struct {
        Name  sql.NullString
    }
    
  3. 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"`
}

Playground

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.

playground

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.