mirror of
https://github.com/tokio-rs/axum.git
synced 2024-12-29 15:49:16 +01:00
Add axum::extract::Query::try_from_uri
(#2058)
Co-authored-by: David Pedersen <david.pdrsn@gmail.com>
This commit is contained in:
parent
cc9629fe88
commit
0ed02a9a46
2 changed files with 62 additions and 4 deletions
|
@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- **breaking:** Only inherit fallbacks for routers nested with `Router::nest`.
|
- **breaking:** Only inherit fallbacks for routers nested with `Router::nest`.
|
||||||
Routers nested with `Router::nest_service` will no longer inherit fallbacks ([#1956])
|
Routers nested with `Router::nest_service` will no longer inherit fallbacks ([#1956])
|
||||||
- **fixed:** Don't remove the `Sec-WebSocket-Key` header in `WebSocketUpgrade` ([#1972])
|
- **fixed:** Don't remove the `Sec-WebSocket-Key` header in `WebSocketUpgrade` ([#1972])
|
||||||
|
- **added:** Add `axum::extract::Query::try_from_uri` ([#2058])
|
||||||
- **added:** Implement `IntoResponse` for `Box<str>` and `Box<[u8]>` ([#2035])
|
- **added:** Implement `IntoResponse` for `Box<str>` and `Box<[u8]>` ([#2035])
|
||||||
|
|
||||||
[#1664]: https://github.com/tokio-rs/axum/pull/1664
|
[#1664]: https://github.com/tokio-rs/axum/pull/1664
|
||||||
|
@ -64,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
[#1868]: https://github.com/tokio-rs/axum/pull/1868
|
[#1868]: https://github.com/tokio-rs/axum/pull/1868
|
||||||
[#1956]: https://github.com/tokio-rs/axum/pull/1956
|
[#1956]: https://github.com/tokio-rs/axum/pull/1956
|
||||||
[#1972]: https://github.com/tokio-rs/axum/pull/1972
|
[#1972]: https://github.com/tokio-rs/axum/pull/1972
|
||||||
|
[#2058]: https://github.com/tokio-rs/axum/pull/2058
|
||||||
|
|
||||||
# 0.6.17 (25. April, 2023)
|
# 0.6.17 (25. April, 2023)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{rejection::*, FromRequestParts};
|
use super::{rejection::*, FromRequestParts};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use http::request::Parts;
|
use http::{request::Parts, Uri};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
/// Extractor that deserializes query strings into some type.
|
/// Extractor that deserializes query strings into some type.
|
||||||
|
@ -55,10 +55,38 @@ where
|
||||||
type Rejection = QueryRejection;
|
type Rejection = QueryRejection;
|
||||||
|
|
||||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||||
let query = parts.uri.query().unwrap_or_default();
|
Self::try_from_uri(&parts.uri)
|
||||||
let value =
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::try_from_uri(&uri).unwrap();
|
||||||
|
/// assert_eq!(result.foo, String::from("hello"));
|
||||||
|
/// assert_eq!(result.bar, 42);
|
||||||
|
/// ```
|
||||||
|
pub fn try_from_uri(value: &Uri) -> Result<Self, QueryRejection> {
|
||||||
|
let query = value.query().unwrap_or_default();
|
||||||
|
let params =
|
||||||
serde_urlencoded::from_str(query).map_err(FailedToDeserializeQueryString::from_err)?;
|
serde_urlencoded::from_str(query).map_err(FailedToDeserializeQueryString::from_err)?;
|
||||||
Ok(Query(value))
|
Ok(Query(params))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,4 +165,32 @@ mod tests {
|
||||||
let res = client.get("/?n=hi").send().await;
|
let res = client.get("/?n=hi").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_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::try_from_uri(&uri).unwrap();
|
||||||
|
assert_eq!(result.foo, String::from("hello"));
|
||||||
|
assert_eq!(result.bar, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_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::try_from_uri(&uri);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue