leptos-rs / leptos

Build fast web applications with Rust.
https://leptos.dev
MIT License
15.96k stars 627 forks source link

DeserializationError when using create_resource of data that use #[serde(deserialize_with = "xxx")] #2603

Closed maxwen closed 3 months ago

maxwen commented 4 months ago

Describe the bug Looks like using custom serde deserializers like

[serde(deserialize_with = "xxx")]

are not used since I get DeserializationError on those attributes when they are used in a create_resource call

Leptos Dependencies

leptos = { version = "0.6", features = ["nightly"] }
leptos_meta = { version = "0.6", features = ["nightly"] }
leptos_actix = { version = "0.6", optional = true }
leptos_router = { version = "0.6", features = ["nightly"] }
serde = { version = "1.0.201", features = ["derive"] }
serde_json = "1.0.117"

To Reproduce

Using a async fn that returns something like

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CurrentWeather {
    #[serde(deserialize_with = "string_from_long")]
    pub dt: String,
}

fn string_from_long<'de, D>(deserializer: D) -> Result<String, D::Error>
    where
        D: Deserializer<'de>,
{
    let long: u64 = Deserialize::deserialize(deserializer)?;
    Ok(long.to_string())
}

This object also used for graphQL queries therefore a long to string mapping is used.

Gives the error
panicked at /home/maxl/.cargo/registry/src/index.crates.io-6f17d22bba15001f/leptos_reactive-0.6.11/src/resource.rs:433:17:
could not deserialize Resource<leptos_axtic_playground::pages::model::WeatherResponse> JSON for ResourceId(1v1): Deserialize(Error("invalid type: string \"1716905610\", expected u64", line: 1, column: 47))

So it seems its not using the serde deserializer? If I remove the custom serializer and change dt to u64 it works as expected and create_resource works

Expected behavior It should not create DeserializationError

luxalpa commented 4 months ago

When leptos sends resources, it first serializes them into JSON using serde, renders that into the HTML sent by the SSR, then it deserializes it again.

The problem is you're using deserialize_with, but not serialize_with. So during the first step, it serializes dt as a String into JSON, then when it deserializes it from JSON again during hydration, it encounters this string when it's actually looking for a u64.

gbj commented 3 months ago

Thanks @luxalpa. This explanation sounds correct to me, and I don't see any need for action here — @maxwen let me know if this needs to be reopened.

maxwen commented 3 months ago

Thx. will try to see if that solves the error

Add: Yes that solved it - thx again