axum crate の FromRequestParts の標準で提供される実装
前回は axum crate の Extractor のトレイトをざっと見ました。
今回は axum crate のビルトイン Extractor の実装、特に FromRequstParts のものを見ていきます。
今回も axum crate のバージョンは 0.8.6 です。
axum crate のビルトイン Extractor とは
axum における Extractor とは FromRequestParts trait または FromRequest trait を実装しているものです。ビルトイン Extractor は axum crate 本体が提供しているそれらの trait の実装です。
今回は FromRequestParts の実装を見ていきます。前回と同様に、 FromRequestParts のドキュメントにある実装を順に見ていきます。
https://docs.rs/axum/0.8.6/axum/extract/trait.FromRequestParts.html
impl<S> FromRequestParts<S> for ()
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/tuple.rs.html#6-15
impl<S> FromRequestParts<S> for ()
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(_: &mut Parts, _: &S) -> Result<(), Self::Rejection> {
Ok(())
}
}
() を返すのみ (何もしません) 。
impl<S> FromRequestParts<S> for Extensions
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#148-157
impl<S> FromRequestParts<S> for Extensions
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(parts.extensions.clone())
}
}
parts.extensions を clone して返すのみ。
impl<S> FromRequestParts<S> for HeaderMap
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#57-66
impl<S> FromRequestParts<S> for HeaderMap
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Ok(parts.headers.clone())
}
}
parts.headers を clone して返すのみ。
impl<S> FromRequestParts<S> for Method
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#19-28
impl<S> FromRequestParts<S> for Method
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Ok(parts.method.clone())
}
}
parts.method を clone して返すのみ。
impl<S> FromRequestParts<S> for Parts
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#137-146
impl<S> FromRequestParts<S> for Parts
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
Ok(parts.clone())
}
}
parts を clone して返すのみ。
impl<S> FromRequestParts<S> for Uri
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#30-39
impl<S> FromRequestParts<S> for Uri
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Ok(parts.uri.clone())
}
}
parts.uri を clone して返すのみ。
impl<S> FromRequestParts<S> for Version
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/request_parts.rs.html#41-50
impl<S> FromRequestParts<S> for Version
where
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
Ok(parts.version)
}
}
parts.version を返すのみ。
impl<S, T1, ..., T16> FromRequestParts<S> for (T1, ..., T16)
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/tuple.rs.html#74
all_the_tuples!(impl_from_request);
macro_rules! impl_from_request {
(
[$($ty:ident),*], $last:ident
) => {
#[allow(non_snake_case, unused_mut, unused_variables)]
impl<S, $($ty,)* $last> FromRequestParts<S> for ($($ty,)* $last,)
where
$( $ty: FromRequestParts<S> + Send, )*
$last: FromRequestParts<S> + Send,
S: Send + Sync,
{
type Rejection = Response;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
$(
let $ty = $ty::from_request_parts(parts, state)
.await
.map_err(|err| err.into_response())?;
)*
let $last = $last::from_request_parts(parts, state)
.await
.map_err(|err| err.into_response())?;
Ok(($($ty,)* $last,))
}
}
// ...
};
}
all_the_tuples macro は前々回に出てきました 。 macro の呼び出しを T1 から T1, .., T16 までの可変のものに対して実行するものです。
今回は impl_from_request macro を all_the_tuples に渡しています。
各引数 (FromRequestParts<S> + Send) に対して from_request_parts して失敗時は err.into_response() し response を返しています。 すべて成功した際は tuple に詰めて返しています。
FromRequestParts の関連型 Rejection は定義から IntoResponse を実装しているので into_response できます。
https://docs.rs/axum/0.8.6/axum/extract/trait.FromRequestParts.html
pub trait FromRequestParts<S>: Sized {
type Rejection: IntoResponse;
// Required method
fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> impl Future<Output = Result<Self, Self::Rejection>> + Send;
}
impl<S, T> FromRequestParts<S> for Option<T>
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/option.rs.html#38-51
impl<S, T> FromRequestParts<S> for Option<T>
where
T: OptionalFromRequestParts<S>,
S: Send + Sync,
{
type Rejection = T::Rejection;
fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> impl Future<Output = Result<Option<T>, Self::Rejection>> {
T::from_request_parts(parts, state)
}
}
OptionalFromRequestParts<S> な T が Option<T> の形で Extractor として指定されているとき、 T::from_request_parts に任せる、と。
OptionFromRequestParts の定義を見ます。
https://docs.rs/axum/0.8.6/axum/extract/trait.OptionalFromRequestParts.html
pub trait OptionalFromRequestParts<S>: Sized {
type Rejection: IntoResponse;
// Required method
fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> impl Future<Output = Result<Option<Self>, Self::Rejection>> + Send;
}
Option が返されるようになっており、取得できない場合に None を返す選択肢があるわけですね。
標準では↓の実装が提供されているようです。
impl<S> OptionalFromRequestParts<S> for MatchedPathimpl<T, S> OptionalFromRequestParts<S> for Extension<T>impl<T, S> OptionalFromRequestParts<S> for Path<T>
impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
https://docs.rs/axum-core/0.5.5/src/axum_core/extract/mod.rs.html#107-117
impl<S, T> FromRequestParts<S> for Result<T, T::Rejection>
where
T: FromRequestParts<S>,
S: Send + Sync,
{
type Rejection = Infallible;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
Ok(T::from_request_parts(parts, state).await)
}
}
通常は失敗時の into_response の呼び出しまでしてしまうところを、Result<T, T::Rejection> の場合は Result のまま返しています。
Extractor のエラーを任意の形に変更したい場合に都合が良いということですね。
おわりに
今回は axum crate の FromRequstParts の標準で提供されている実装を見ました。
次回は FromRequest の標準で提供されている実装を見ていきます。
Discussion