I am receiving JSON from an API and the response can be one of 30 types. Each type has a unique set of fields, but all responses have a field type
which states which type it is.
My approach is to use serde. I create a struct for each response type and make them decodable. Once I have that how do I choose which struct should be used for a freshly received message?
At the moment, I've created another struct TypeStruct
with only a single field for type
. I decode the JSON into a TypeStruct
, then choose the appropriate struct for received message, based on type value, and decode the message again.
I would like to get rid of this decoding duplication.
You can use the existing enum deserialization. I'll give a step by step example to deserialize your format to the following enum:
#[derive(Debug, PartialEq, Eq, Deserialize)]
enum MyType {
A {gar: ()},
B {test: i32},
C {blub: String},
}
Start with an example json string:
let json = r#"{"type": "B", "test": 42}"#;
Turn it into a Value
enum
let mut json: serde_json::Value = serde_json::from_str(json).unwrap();
Rip out the type
field
let type_ = {
let obj = json.as_object_mut().expect("object");
let type_ = obj.remove("type").expect("`type` field");
if let serde_json::Value::String(s) = type_ {
s
} else {
panic!("type field not a string");
}
};
Create the "proper" enum json. A struct with a single field where the name of the field is the enum variant and the value of the field is the variant value
let mut enum_obj = std::collections::BTreeMap::new();
enum_obj.insert(type_, json);
let json = serde_json::Value::Object(enum_obj);
Use the generated json deserializer to turn the json into a value of your enum
let obj: MyType = serde_json::from_value(json).unwrap();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With