mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-22 00:00:17 +02:00
Break up extract.rs (#103)
This breaks up `extract.rs` into several smaller submodules. The public API remains the same. This is done in prep for adding more tests to extractors which would get messy if they were all in the same file.
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
use super::{rejection::*, FromRequest, RequestParts};
|
||||
use async_trait::async_trait;
|
||||
use std::{ops::Deref, str::FromStr};
|
||||
|
||||
/// Extractor that will get captures from the URL and parse them.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use axum::{extract::UrlParams, prelude::*};
|
||||
/// use uuid::Uuid;
|
||||
///
|
||||
/// async fn users_teams_show(
|
||||
/// UrlParams(params): UrlParams<(Uuid, Uuid)>,
|
||||
/// ) {
|
||||
/// let user_id: Uuid = params.0;
|
||||
/// let team_id: Uuid = params.1;
|
||||
///
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show));
|
||||
/// # async {
|
||||
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// Note that you can only have one URL params extractor per handler. If you
|
||||
/// have multiple it'll response with `500 Internal Server Error`.
|
||||
#[derive(Debug)]
|
||||
pub struct UrlParams<T>(pub T);
|
||||
|
||||
macro_rules! impl_parse_url {
|
||||
() => {};
|
||||
|
||||
( $head:ident, $($tail:ident),* $(,)? ) => {
|
||||
#[async_trait]
|
||||
impl<B, $head, $($tail,)*> FromRequest<B> for UrlParams<($head, $($tail,)*)>
|
||||
where
|
||||
$head: FromStr + Send,
|
||||
$( $tail: FromStr + Send, )*
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = UrlParamsRejection;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let params = if let Some(params) = req
|
||||
.extensions_mut()
|
||||
.and_then(|ext| {
|
||||
ext.get_mut::<Option<crate::routing::UrlParams>>()
|
||||
})
|
||||
{
|
||||
if let Some(params) = params {
|
||||
params.0.clone()
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
} else {
|
||||
return Err(MissingRouteParams.into())
|
||||
};
|
||||
|
||||
if let [(_, $head), $((_, $tail),)*] = &*params {
|
||||
let $head = if let Ok(x) = $head.as_str().parse::<$head>() {
|
||||
x
|
||||
} else {
|
||||
return Err(InvalidUrlParam::new::<$head>().into());
|
||||
};
|
||||
|
||||
$(
|
||||
let $tail = if let Ok(x) = $tail.as_str().parse::<$tail>() {
|
||||
x
|
||||
} else {
|
||||
return Err(InvalidUrlParam::new::<$tail>().into());
|
||||
};
|
||||
)*
|
||||
|
||||
Ok(UrlParams(($head, $($tail,)*)))
|
||||
} else {
|
||||
Err(MissingRouteParams.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_parse_url!($($tail,)*);
|
||||
};
|
||||
}
|
||||
|
||||
impl_parse_url!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
|
||||
|
||||
impl<T> Deref for UrlParams<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user