Make Path extractor work with Deserialize impls using &str (#990)

* `Path` extractor works with `Deserialize` impls using `&str`

Before this change the extractor `Path<Test>` would fail if the
`Deserialize` implementation of `Test` was calling
`Deserializer::deserialize_str()`.

Now we use `Visitor::visit_borrowed_str()` instead of
`Visitor::visit_str()` which is also recommended in the guide to
implement a deserializer [1].

[1]: https://serde.rs/impl-deserializer.html

* fixup! `Path` extractor works with `Deserialize` impls using `&str`

* add test for percent decoding

Co-authored-by: David Pedersen <[email protected]>
This commit is contained in:
Thomas Scholtes
2022-05-03 18:44:58 +00:00
committed by GitHub
co-authored by David Pedersen
parent d1043db254
commit 8cc052f38b
2 changed files with 28 additions and 1 deletions
+25
View File
@@ -514,4 +514,29 @@ mod tests {
"No paths parameters found for matched route. Are you also extracting `Request<_>`?"
);
}
#[tokio::test]
async fn str_reference_deserialize() {
struct Param(String);
impl<'de> serde::Deserialize<'de> for Param {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = <&str as serde::Deserialize>::deserialize(deserializer)?;
Ok(Param(s.to_owned()))
}
}
let app = Router::new().route("/:key", get(|param: Path<Param>| async move { param.0 .0 }));
let client = TestClient::new(app);
let res = client.get("/foo").send().await;
assert_eq!(res.text().await, "foo");
// percent decoding should also work
let res = client.get("/foo%20bar").send().await;
assert_eq!(res.text().await, "foo bar");
}
}