I recently switched to using url::Url
in my api wrapper structure instead of String
. However one big problem I have is that whenever a field has ""
it doesn’t give me a None, instead it throws a parse error. This makes the wrapper unusable. I made an issue for this, but are there any serde attributes I can use to temporarily circumvent this?
Erroring out when given the empty string is the correct behaviour from the url
crate, so you might want to look into the #[serde(deserialize_with = "...")]
attribute to add your own deserializing logic.
Maybe something like this will work?
use serde::de::{Deserialize, Deserializer, Error as _};
use std::borrow::Cow;
use url::Url;
#[derive(Debug, serde::Deserialize)]
struct Foo {
#[serde(deserialize_with = "deserialize_url")]
url: Option<Url>,
}
fn deserialize_url<'de, D: Deserializer<'de>>(de: D) -> Result<Option<Url>, D::Error> {
// first, deserialize into a temporary value so we can do the empty string
// test.
let intermediate = <Option<Cow<'de, str>>>::deserialize(de)?;
// now, try to parse the string as a URL, using pattern matching to handle
// the empty string case
match intermediate.as_deref() {
None | Some("") => Ok(None),
Some(non_empty_string) => Url::parse(non_empty_string)
.map(Some)
.map_err(D::Error::custom),
}
}
fn main() {
let json = r#"{ "url": "" }"#;
let foo: Foo = serde_json::from_str(json).unwrap();
println!("{foo:?}");
}
2 Likes
Erroring out when given the empty string is the correct behaviour
Yup that's what I expected I understand that it can't really be implemented in a 'direct' way.
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.