'Map part of the JSON to struct

I have weather data API call and some json basic conversion:

use serde_json::{Value};

...

let resp = reqwest::get(WEATHER_API_URL).await?.text().await?;
let json: Value = serde_json::from_str(&resp)?;

which produces Object result:

Object({
    ...
    "clouds": Object({
        "all": Number(
            0,
        ),
    }),
    "id": Number(
        2950159,
    ),
    "main": Object({
        "feels_like": Number(
            287.04,
        ),
        "humidity": Number(
            34,
        ),
        "pressure": Number(
            1015,
        ),
        "temp": Number(
            288.56,
        ),
        "temp_max": Number(
            290.38,
        ),
        "temp_min": Number(
            287.03,
        ),
    })
    ...

I want only main data from that^ given shape. I have a structure for that:

use serde::{Deserialize, Serialize};

...

#[derive(Debug, Serialize, Deserialize)]
struct Main {
  temp: f32,
  feels_like: f32,
  temp_min: f32,
  temp_max: f32,
  pressure: f32,
  humidity: f32
}

How is it possible to map some part of json (the main object part) with my Main struct? Maybe there are better ways to accomplish such scenario? where basically what I need is grab some data from JSON and then be able to use it in my code. The key thing in my case is that my json has complex structure with nested entities and I can't map it one-to-one.



Solution 1:[1]

You can have a structs like:

#[derive(Debug, Serialize, Deserialize)]
struct MainWrapper {
  main: Main,
}

#[derive(Debug, Serialize, Deserialize)]
struct Main {
  temp: f32,
  feels_like: f32,
  temp_min: f32,
  temp_max: f32,
  pressure: f32,
  humidity: f32
}

let deserialized: MainWrapper = serde_json::from_str(&json)?;

Or if you don't want to deal with MainWrapper in your code:

impl<'de> Deserialize<'de> for Main {
    fn deserialize<D>(deserializer: D) -> Result<Main, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Debug, Serialize, Deserialize)]
        struct MainWrapper {
           main: MainInner,
        }

        // You can generally generate such copies with macros

        #[derive(Debug, Serialize, Deserialize)]
        struct MainInner {
           temp: f32,
           feels_like: f32,
           temp_min: f32,
           temp_max: f32,
           pressure: f32,
           humidity: f32
        }
        impl From<MapInner> for Main {
           // ...
        }

        let deserialized: MainWrapper = Deserialize::deserialize(deserializer)?;
        Ok(deserialized.main.into())
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1