Search code examples
rustserde

How to get at one particular item in JSON file using serde_json without deriving structs?


I have a complex JSON file and I'd like to extract only a single value out of it. I could define all of the structs and derive Deserialize on all of them, but I'd like to just write a little manual code to pull that one value out. The Serde documentation, quite frankly, just confused me.

My JSON content has the following layout:

{
  "data": [
    {
      "hostname": "a hostname"
    }
  ]
}

I'm looking for the value navigated to by going into data, then taking the first element of the array, and taking the value of hostname.

In Haskell, I'd do it like this:

newtype Host = Host Text

instance FromJSON Host where
    parseJSON (Object o) = (return . Host) <=< (.: "hostname") <=< (fmap (!! 0) . parseJSON) <=< (.: "data") $ o
    parseJSON _ = mzero

What's the equivalent for Serde?


Solution

  • The serde_json crate provides types for generic JSON values with serde_json::Value:

    use serde_json::Value;
    
    // input variable
    let input: &str = "{...}";
    
    // parse into generic JSON value
    let root: Value = serde_json::from_str(input)?;
    
    // access element using .get()
    let hostname: Option<&str> = root.get("data")
        .and_then(|value| value.get(0))
        .and_then(|value| value.get("hostname"))
        .and_then(|value| value.as_str());
    
    // hostname is Some(string_value) if .data[0].hostname is a string,
    // and None if it was not found
    println!("hostname = {:?}", hostname); // = Some("a hostname")
    

    (full playground example)