英文:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论