Search code examples
jsonrustserde

How can I use serde json on a json object with variable key names


I am aware of the JSON value which can be used for unknown JSON.

What I have is a mostly structured JSON object like this:

{
    "error": [],
    "result": {
        "NAME_X": {
            "prop_one": "something",
            "prop_two": "something",
            "decimals": 1,
            "more_decimals": 2
        },
        "NAME_A": {
            "prop_one": "test",
            "prop_two": "sdfsdf",
            "decimals": 2,
            "more_decimals": 5
        },
        "ARBITRARY": {
            "prop_one": "something else",
            "prop_two": "blah",
            "decimals": 3,
            "more_decimals": 6
        }
}

So the inside object with fields prop_one, prop_two, decimals and more_decimals has a clear structure, but the outer name field/key (NAME_X, NAME_A, ARBITRARY) is unknown in advance.

What is the most straight forward way to parse this so I can use strongly typed variables/deserialization on the inner structure? I also still need to capture those unknown name fields.


Solution

  • You can deserialize into a map whose keys will be strings ("NAME_X", etc.):

    use std::collections::HashMap;
    use serde::Deserialize;
    use serde_json::Result;
    
    #[derive(Debug, Deserialize)]
    struct InThing {
        prop_one: String,
        prop_two: String,
        decimals: u16,
        more_decimals: i32,
    }
    #[derive(Debug, Deserialize)]
    struct OutThing {
        error: Vec<u8>,
        result: HashMap<String, InThing>,
    }
    
    fn main() {
        let data = r#"
            {
                "error": [],
                "result": {
                    "NAME_X": {
                        "prop_one": "something",
                        "prop_two": "something",
                        "decimals": 1,
                        "more_decimals": 2
                    },
                    "NAME_A": {
                        "prop_one": "test",
                        "prop_two": "sdfsdf",
                        "decimals": 2,
                        "more_decimals": 5
                    },
                    "ARBITRARY": {
                        "prop_one": "something else",
                        "prop_two": "blah",
                        "decimals": 3,
                        "more_decimals": 6
                    }
                }
            }
            "#;
        let thing: OutThing = serde_json::from_str(data).unwrap(); 
        dbg!(thing);
    }
    

    playground