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

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

Handling PATCH partial updates when a key is not present

问题

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

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

  1. type UpdateUserDTO struct {
  2. ID uuid.UUID
  3. FirstName string
  4. LastName string
  5. ImageURL *string
  6. }

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

  1. { "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.

  1. type UpdateUserDTO struct {
  2. ID uuid.UUID
  3. FirstName string
  4. LastName string
  5. ImageURL *string
  6. }

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

  1. { 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,还是提供了非空值。

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

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


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

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

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.

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

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.

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

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:

确定