Unable to deserialize a json with random obj

I have the following JSON

{
   "count":713,
   "devices":{
      "2":{
         "device_id":"2",
         "hostname":"device2",
         "status_type":"ok",
         "uptime":"9100423",
         "last_rebooted":"1670234026"
      },
      "6":{
         "device_id":"6",
         "hostname":"device6",
         "status_type":"ok",
         "uptime":"9209422",
         "last_rebooted":"1990234026"
      }
   }
}

I am using the following structs.

#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Obj {
    pub count: i64,
    pub devices: Devices,
}

#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Devices {
    //#[serde(rename = "2")]
    pub device: Device,
}

#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Device {
    #[serde(rename = "device_id")]
    pub device_id: String,
    pub hostname: String,
    #[serde(rename = "status_type")]
    pub status_type: String,
    pub uptime: String,
    #[serde(rename = "last_rebooted")]
    pub last_rebooted: String,
}

The issue is that the JSON device id's are series of numbered strings, as shown above ("2", "6".. and so on). When I uncomment //#[serde(rename = "2")] I can deserialize just 1 device that matches the "2". But I want to match all the numbered strings ("2", "6", and others...) into structs.

I couldn't figure out how to accomplish this.

The structure of your structs doesn't really match your json as it's missing a way to capture that devices could have many values.

The simplest solution would be to use a HashMap for your devices and remove the Devices struct.
e.g.

#[derive(Default, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Obj {
    pub count: i64,
    pub devices: HashMap<String, Device>,
}
3 Likes

I tried this method, but it throws an error shown below.

let result: Obj = client
        .get(url)
        .basic_auth(user_name, password)
        .send()?
        .json()?;
Err(
    reqwest::Error {
        kind: Decode,
        source: Error("invalid type: null, expected a string", line: 1, column: 50161),
    },
)

My best bet, without seeing the data you're decoding there, is that one or more of the fields in Device should be Option<...> to account for null values.

e.g. if last_rebooted can be null you need to have

pub last_rebooted: Option<String>,

and the same for any other field that could be null

2 Likes

Did you read the documentation of Serde? All of this basic stuff is covered there in great detail.

Excellent feedback @tristan :smile: your feedback regarding a non-string value was the culprit. Just to test your idea I changed all the types in Device to Value types and it worked. So now I need to figure out which types needs the Option and proceed from there. Excellent, bravo.

Also, could you explain to me why you decided to use the HashMap? Whats the idea behind this?

I did read and still do re-read the doc. But the very basic stuffs sometimes appear like a mountain for a noob like me, until a fellow helps me nudge the right way :smile:

Unless serde's special attributes are applied, you just need to match the structure of your UDTs with the structure of the JSON exactly, and that is all.

2 Likes

There's not really much to say. Your devices type is a JSON object with random keys. A HashMap is just the simplest thing that fits this structure.

3 Likes

Thanks. Truly appreciate your help. Plenty of learning to do :smiley:

Thanks @tristan Truly appreciate your help. Plenty of learning to do :smiley:

Serialization, in computer programming terms, means transforming a data type to a serialized format (in your case, JSON).

Deserialization is the inverse process: from a serialized format to a data type.

Since you are learning to serialize/deserialize to/from JSON, you should familiarize yourself with how the JSON values map to data types and vice versa.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.