I'd like to use Serde to parse some JSON as part of a HTTP PATCH request. Since PATCH requests don't pass the entire object, only the relevant data to update, I need the ability to tell between a value that was not passed, a value that was explicitly set to null
, and a value that is present.
I have a value object with multiple nullable fields:
struct Resource {
a: Option<i32>,
b: Option<i32>,
c: Option<i32>,
}
If the client submits JSON like this:
{"a": 42, "b": null}
I'd like to change a
to Some(42)
, b
to None
, and leave c
unchanged.
I tried wrapping each field in one more level of Option
:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
a: Option<Option<i32>>,
b: Option<Option<i32>>,
c: Option<Option<i32>>,
}
This does not make a distinction between b
and c
; both are None
but I'd have wanted b
to be Some(None)
.
I'm not tied to this representation of nested Option
s; any solution that can distinguish the 3 cases would be fine, such as one using a custom enum.
Building off of E_net4's answer, you can also create an enum for the three possibilities:
This can then be used as:
Unfortunately, you still have to annotate each field with
#[serde(default)]
(or apply it to the entire struct). Ideally, the implementation ofDeserialize
forPatch
would handle that completely, but I haven't figured out how to do that yet.Quite likely, the only way to achieve that right now is with a custom deserialization function. Fortunately, it is not hard to implement, even to make it work for any kind of field:
Then each field would be annotated as thus:
You also need to annotate the struct with
#[serde(default)]
, so that empty fields are deserialized to an "unwrapped"None
. The trick is to wrap present values aroundSome
.Serialization relies on another trick: skipping serialization when the field is
None
:Playground with the full example. The output: