处理 PATCH 部分更新时,如果键不存在

huangapple go评论79阅读模式
英文:

Handling PATCH partial updates when a key is not present

问题

我正在努力解决如何解决这个问题。

我有一个User结构体,它有几个字段。然而,当解码一个JSON对象用于PATCH用户调用时,缺少的键会导致值被设置为*nil。相应的数据库属性的类型是TEXT NULL,所以当键缺失时,结果将始终存储为NULL。

type UpdateUserDTO struct {
  ID         uuid.UUID
  FirstName  string
  LastName   string
  ImageURL  *string
}

ImageURL可以是nil,但当这个对象从客户端发送过来时:

{ "firstName": "Jimmy" }

这会解码成ImageURL = nil,因为JSON中没有imageUrl

我如何处理部分更新,而不是使用map[string]struct{}来检查每个字段的存在呢?

英文:

I'm trying to figure out how to get past this issue.

I have a User struct and it has a few fields on it. However, when decoding a JSON object for a PATCH users call, a missing key leads to the value set as *nil. The corresponding database attribute is of type TEXT NULL, so the result will always be stored as NULL when the key is missing.

type UpdateUserDTO struct {
  ID         uuid.UUID
  FirstName  string
  LastName   string
  ImageURL  *string
}

ImageURL can be nil, but when this object is sent from clients:

{ firstName: "Jimmy" }

This decodes into ImageURL = nil because the imageUrl was not present in JSON.

How can I handle partial updates without resorting to checking the presence of each field using a map[string]struct{} instead of my DTO?

答案1

得分: 1

你可以实现一个自定义的json.Unmarshaler来确定字段是完全省略、提供了但其值为null,还是提供了非空值。

type OptString struct {
    IsValid bool
    String  *string
}

// 如果这种类型的字段在传入的JSON中没有对应的字段,则不会调用此方法,IsValid标志的值将保持为`false`。
func (s *OptString) UnmarshalJSON(data []byte) error {
    if err := json.Unmarshal(data, &s.String); err != nil {
        return err
    }
    s.IsValid = true
    return nil
}
type UpdateUserDTO struct {
    ID        uuid.UUID
    FirstName string
    LastName  string
    ImageURL  OptString
}

https://go.dev/play/p/hvS5E46sgkD


另一种方法是,在解组JSON之前,将Go字段的值设置为_当前_数据库列的值。json.Decoder(由json.Unmarshal使用)如果传入的JSON不包含匹配的字段,则不会“触及”目标的字段。

dto := loadUpdateUserDTOFromDB(conn)
if err := json.Unmarshal(data, dto); err != nil {
    return err
}

https://go.dev/play/p/grJhr4P7sgQ

英文:

You can implement a custom json.Unmarshaler to determine whether the field was omitted entirely, was provided but its value was null, or was provided with non-null value.

type OptString struct {
    IsValid bool
    String  *string
}

// If a field with this type has no corresponding field in the
// incoming JSON then this method will not be invoked and the
// IsValid flag's value will remain `false`.
func (s *OptString) UnmarshalJSON(data []byte) error {
    if err := json.Unmarshal(data, &s.String); err != nil {
        return err
    }
    s.IsValid = true
    return nil
}
type UpdateUserDTO struct {
    ID        uuid.UUID
    FirstName string
    LastName  string
    ImageURL  OptString
}

https://go.dev/play/p/hvS5E46sgkD


An alternative approach, one that does not require a custom type, would be to set the Go field's value to the current database column's value just before unmarshaling the JSON. The json.Decoder (used by json.Unmarshal) will not "touch" a target's field if the incoming JSON doesn't contain a matching field.

dto := loadUpdateUserDTOFromDB(conn)
if err := json.Unmarshal(data, dto); err != nil {
    return err
}

https://go.dev/play/p/grJhr4P7sgQ

huangapple
  • 本文由 发表于 2023年3月10日 13:46:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75692627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定