15

I have a data stream of JSON where some JSON objects may be missing certain fields or have fields I am unaware of in advance.

My solution is to use:

let v: Value = serde_json::from_str(data)?;

How do I handle accessing the field stuff? If I know it exists, I can use:

v["stuff"]

How do I handle the case stuff isn't a field in my data?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
James Smith
  • 249
  • 1
  • 2
  • 8

2 Answers2

19

My solution is to use [serde_json::Value]

I'd still use type-driven serialization, wrapping the potentially-missing field in an Option.

use serde::Deserialize; // 1.0.101
use serde_json; // 1.0.40

#[derive(Debug, Deserialize)]
struct Data {
    required: i32,
    missing: Option<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let data = r#"{"required": 42, "extra": true}"#;
    let data = serde_json::from_str::<Data>(data)?;
    println!("{:?}", data);

    let data = r#"{"required": 42, "extra": true, "missing": "cow"}"#;
    let data = serde_json::from_str::<Data>(data)?;
    println!("{:?}", data);

    Ok(())
}
Data { required: 42, missing: None }
Data { required: 42, missing: Some("cow") }

If you have fields where the name cannot be known at compile time, you can use serde_json::Value in addition to this solution. See How can I use Serde's custom (de)serialization to update a subset of arbitrary input?

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
16

Accessing a missing field by the Index implementation of Value (i.e. v["stuff"]) will panic if the field does not exist. Instead, use Value::get, which returns an Option:

if let Some(field) = v.get("stuff") {
    println!("field = {:?}", field);
} else {
    println!("field is missing");
}
Peter Hall
  • 53,120
  • 14
  • 139
  • 204