Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add axum::extract::Query::try_from_uri #2058

Merged
merged 9 commits into from
Jul 3, 2023
61 changes: 60 additions & 1 deletion axum/src/extract/query.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{rejection::*, FromRequestParts};
use async_trait::async_trait;
use http::request::Parts;
use http::{request::Parts, Uri};
use serde::de::DeserializeOwned;

/// Extractor that deserializes query strings into some type.
Expand Down Expand Up @@ -62,6 +62,37 @@ where
}
}

impl<T> Query<T>
where
T: DeserializeOwned,
{
/// Attempts to construct a [`Query`] from a reference to a [`Uri`].
///
/// # Example
/// ```
/// use axum::extract::Query;
/// use http::Uri;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct ExampleParams {
/// foo: String,
/// bar: u32,
/// }
///
/// let uri: Uri = "http://example.com/path?foo=hello&bar=42".parse().unwrap();
/// let result: Query<ExampleParams> = Query::from_uri(&uri).unwrap();
/// assert_eq!(result.foo, String::from("hello"));
/// assert_eq!(result.bar, 42);
/// ```
pub fn from_uri(value: &Uri) -> Result<Self, QueryRejection> {
let query = value.query().unwrap_or_default();
let params: T =
serde_urlencoded::from_str(query).map_err(FailedToDeserializeQueryString::from_err)?;
Ok(Query(params))
}
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
}

axum_core::__impl_deref!(Query);

#[cfg(test)]
Expand Down Expand Up @@ -137,4 +168,32 @@ mod tests {
let res = client.get("/?n=hi").send().await;
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
}

#[test]
fn test_from_uri() {
#[derive(Deserialize)]
struct TestQueryParams {
foo: String,
bar: u32,
}
let uri: Uri = "http://example.com/path?foo=hello&bar=42".parse().unwrap();
let result: Query<TestQueryParams> = Query::from_uri(&uri).unwrap();
assert_eq!(result.foo, String::from("hello"));
assert_eq!(result.bar, 42);
}

#[test]
fn test_from_uri_with_invalid_query() {
#[derive(Deserialize)]
struct TestQueryParams {
_foo: String,
_bar: u32,
}
let uri: Uri = "http://example.com/path?foo=hello&bar=invalid"
.parse()
.unwrap();
let result: Result<Query<TestQueryParams>, _> = Query::from_uri(&uri);

assert!(result.is_err());
}
}