I am currently trying to simplify for downstream developers an API client I writing. The REST API I am consuming from has a root key "response" and then basically the entity fields there after.
For example, the struct below might be what I want to deserialize from the payload.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Example {
pub field1: String
pub field2: String
pub field3: u32
}
However in the naive case I have to do something like:
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Single<T> {
pub response: T
}
and
-> Response<Single<Example>>
might be what comes back from the client.
I don't want consumers of the client having to deal with the "response" root key represented by the "Single" struct.
Exploring this I landed on the solution talked about here - Add a #[serde(root = "<something>")] for deserializing Structs under alternate root names · Issue #1345 · serde-rs/serde · GitHub. It uses a custom deserializer and visitor to automagically remove the "response" root key and now I can just do Response<Example>
on my client returns.
Now this technique works fine, but I now want to extend a solution to handle the case of Example being wrapped OR not wrapped with a response root key - as this Example object is used sans wrapper in other places of the API.
I'm trying to work out how this is possible. One idea I had was in the WrapperVistor from - Add a #[serde(root = "<something>")] for deserializing Structs under alternate root names · Issue #1345 · serde-rs/serde · GitHub - if the wrapper key is missing I can deserialize the Example object directly. However the serde::de::MapAccess
type is stateful (it remembers it was iterated over) and there appears to be no way to reset it to the beginning. Likewise there doesn't seem to be a way to backtrack or reset a deserializer. Another option was the deserialize to a json::Value and use get to see if the "response" key is present and take the appropriate action, but I haven't got this working yet.
I'm fairly new to rust so I feel like there are other options I'm not aware of. Would love to get some knowledgable guidance. Am I just fighting the canonical way to do this is rust?