😽

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.extensionsclone して返すのみ。

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.headersclone して返すのみ。

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.methodclone して返すのみ。

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())
    }
}

partsclone して返すのみ。

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.uriclone して返すのみ。

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>TOption<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 MatchedPath
  • impl<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 の標準で提供されている実装を見ていきます。

GitHubで編集を提案
ドクターメイト

Discussion