🦀

AxumでHandlerが自動実装出来ない時

2024/07/06に公開

この記事の対象者と目標

  1. 対象者
    • Axumを使い始めたばかりの方
    • Handlerトレイト自動実装ができなくて困っている方
  2. 目標
    Handlerトレイト自動実装の条件を理解する

handlerとは

RustでAxumを使っていく上で、ハンドラーは重要な要素の一つです。
Routerと合わせて使用することで、アプリケーションを構築していくことができます。

Handlerトレイト実装条件と注意点

実装条件

Handlerトレイトは基本的には自動的に実装されます。
条件は以下のようになります。

  1. 非同期関数であること
  2. 0~16個のextractorsを引数を取る関数
  3. IntoResponseトレイトを実装したものを返す関数

IntoResponseを実装したもの

IntoResponseを実装したものは&'static strStringVec<u8>StatusCodeタプルなど様々です 。
詳細はこちらのImplementations on Foreign Types以降に書いてあります。
https://docs.rs/axum/latest/axum/response/trait.IntoResponse.html

注意点

特に気を付けるべき点は引数です。
extractorは以下の2つのトレイトを実装したものです。

  1. FromRequestを実装したもの
    例)Json<T>Form<T>
  2. FromRequestPartsを実装したもの
    例)Path<T>Query<T>Extension<T>

このFromRequestが時に気を付けなければならなく、FromRequestを実装したものはhandler関数の引数の一番最後でなければなりません。
実際の定義は以下のようになっています。

impl<F, Fut, S, Res, M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> Handler<(M, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16), S> for F
where
    F: FnOnce(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16) -> Fut + Clone + Send + 'static,
    Fut: Future<Output = Res> + Send,
    S: Send + Sync + 'static,
    Res: IntoResponse,
    T1: FromRequestParts<S> + Send,
    T2: FromRequestParts<S> + Send,
    T3: FromRequestParts<S> + Send,
    T4: FromRequestParts<S> + Send,
    T5: FromRequestParts<S> + Send,
    T6: FromRequestParts<S> + Send,
    T7: FromRequestParts<S> + Send,
    T8: FromRequestParts<S> + Send,
    T9: FromRequestParts<S> + Send,
    T10: FromRequestParts<S> + Send,
    T11: FromRequestParts<S> + Send,
    T12: FromRequestParts<S> + Send,
    T13: FromRequestParts<S> + Send,
    T14: FromRequestParts<S> + Send,
    T15: FromRequestParts<S> + Send,
    // ⚠️ここに注目!!!!
    T16: FromRequest<S, M> + Send,

理由はJsonなどはdeserializeなど解析する必要があり、時間がかかるなどが挙げられます。
また独自でextractorを実装するときはFromRequestPartsとして実装する方がいいと思っています。

実装例

  1. 自動実装成功例
async fn handler(
Path(id): Path<i32>,
State(app_state): State<AppState>,
// Jsonが一番最後にある!!
Json(payload): Json<User>,
) -> impl IntoResponse {
    // do something
}
  1. 自動実装失敗例
async fn handler(
// Jsonが最後にない!!
Json(payload): Json<User>,
Path(id): Path<i32>,
State(app_state): State<AppState>,
) -> impl IntoResponse {
    // do something
}

まとめ

Handlerトレイト自動実装には以下の条件がある。

  1. 非同期関数であること
  2. 0~16個のextractorsを引数を取る関数
  3. IntoResponseトレイトを実装したものを返す関数

また、引数についてはJson<T>Form<T>などのFromRequestを実装したものは関数の引数の一番最後にする必要がある。

Discussion