type A struct {
Id int64
Email sql.NullString
Phone sql.NullString
}
假设我在数据库中有一条记录
A{1, "x@x.com", "1112223333"}
通过PUT发送更新请求
curl -X PUT -d '{"Email": "y@y.com", "Phone": null}' http://localhost:3000/a/1
这是 psuedo算法,它可以处理完整的PUT请求(即更新记录A的所有字段 - 但它会导致PATCH请求语义出现困难 - 增量更新)
- 将json解组为空记录
a := A{}
json.Unmarshal([]byte(request.body), &a)
- 从数据库加载记录
aFromDb = <assume we got record from db> //A{1, "x@x.com", "1112223333"}
- 比较a和aFromDB
- 注意电子邮件更改并将其设置在aFromDb上 - 确定
- 注意电话号码的变化 - 但等一下!它是明确地在JSON中设置为NULL还是甚至不包含在JSON中?即是json请求 - {“电子邮件”:“y @ y.com”,“电话”:null}或者它是{“电子邮件”:“y@y.com”}?
我们怎样才能通过查看unmarshaled json进入struct a?
还有另一种方法可以通过rest进行更新(使用补丁语义)吗?我正在寻找一种通用的方法(不依赖于特定的结构)。
答案 0 :(得分:0)
尝试将此标记添加到结构中:
type A struct {
Id int64 `json:"Id,omitempty"`
Email sql.NullString `json:"Email,omitempty"`
Phone sql.NullString `json:"Phone,omitempty"`
}
这样,如果你是序列化并且字段为空,那么json将不包含该字段。
虽然反序列化虽然该字段将具有值或者它将具有该类型的默认值(指针为Nil或字符串为空字符串)。
答案 1 :(得分:0)
我为此创建了一个单独的数据类型。此示例适用于int64(实际上是字符串编码的int64),但您也可以轻松地将其更改为字符串。其背后的想法是,只有在JSON中存在值时才会调用UnmarshalJSON
方法。该类型将实现Marshaler和Unmarshaler。
// Used as a JSON type
//
// The Set flag indicates whether an unmarshaling actually happened on the type
type RequiredInt64 struct {
Set bool
Int64 int64
}
func (r RequiredInt64) MarshalJSON() ([]byte, error) {
lit := strconv.FormatInt(r.Int64, 10)
return json.Marshal(lit)
}
func (r *RequiredInt64) UnmarshalJSON(raw []byte) error {
var lit string
var err error
if err = json.Unmarshal(raw, &lit); err != nil {
return err
}
r.Int64, err = strconv.ParseInt(lit, 10, 64)
if err != nil {
return err
}
r.Set = true
return nil
}
因此,如果Set
为false,则表示该值不存在于JSON中。
答案 2 :(得分:0)
您可以编写自己的结构编组/ uinmarshalling并对内部的原始响应做出反应,尽管检查这些函数正在操作的内容可能并不明显。
或者,您不能在字段中使用omitempty并强制填充空填充字段。
或者,也许可以利用不同的修补方式,也许是http://jsonpatch.com/,这在修改的性质上更为明确。这将要求客户更多地了解变化的状态,而不是对put的理解。