Skip to content

Commit

Permalink
Merge branch 'tokio-rs:main' into clean-oauth-anyhow
Browse files Browse the repository at this point in the history
  • Loading branch information
rsdlt committed Jul 3, 2023
2 parents e82836d + 0ed02a9 commit a4093db
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Routers nested with `Router::nest_service` will no longer inherit fallbacks ([#1956])
- **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])

[#1664]: https://github.com/tokio-rs/axum/pull/1664
Expand All @@ -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
[#1956]: https://github.com/tokio-rs/axum/pull/1956
[#1972]: https://github.com/tokio-rs/axum/pull/1972
[#2058]: https://github.com/tokio-rs/axum/pull/2058

# 0.6.17 (25. April, 2023)

Expand Down
2 changes: 1 addition & 1 deletion axum/src/docs/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ It doesn't matter whether you return `Err(StatusCode::NOT_FOUND)` or
axum.

Instead of a direct `StatusCode`, it makes sense to use intermediate error type
that can ultimately be converted to `Reponse`. This allows using `?` operator
that can ultimately be converted to `Response`. This allows using `?` operator
in handlers. See those examples:

* [`anyhow-error-response`][anyhow] for generic boxed errors
Expand Down
64 changes: 60 additions & 4 deletions 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 @@ -55,10 +55,38 @@ where
type Rejection = QueryRejection;

async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
let query = parts.uri.query().unwrap_or_default();
let value =
Self::try_from_uri(&parts.uri)
}
}

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)?;
Ok(Query(value))
Ok(Query(params))
}
}

Expand Down Expand Up @@ -137,4 +165,32 @@ mod tests {
let res = client.get("/?n=hi").send().await;
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());
}
}
2 changes: 1 addition & 1 deletion axum/src/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
//! ```
//!
//! Instead of a direct `StatusCode`, it makes sense to use intermediate error type
//! that can ultimately be converted to `Reponse`. This allows using `?` operator
//! that can ultimately be converted to `Response`. This allows using `?` operator
//! in handlers. See those examples:
//!
//! * [`anyhow-error-response`][anyhow] for generic boxed errors
Expand Down

0 comments on commit a4093db

Please sign in to comment.