ys memos
Blog

Rustのaxumのhandlerでカスタムエラーを戻り値にする


rust

2025/05/12


Rustのコードでよく thiserrorを使ってErrorの伝搬を楽にしているのだが、 axumのhandlerでは、axum::response::Responseそのもの、あるいは、axum::response::IntoResponseを実装した型でなければならない。


thiserror::Errorを実装した型をそのままhandlerのResultには渡せないので、axum::response::IntoResponseの実装を行うことで、handlerのResultに渡せるようにする。

返却するための型(ここでは ApiError)は、 into_response()内部に書いても構わない。が、 serde::Serializeは必要である。

また、APIのレスポンスに詳細の情報を含めないようにするために、 matchで分岐するのもよいかもしれない。

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("Io error: {0}")]
    Io(#[from] std::io::Error),

    #[error("custom error: {0}")]
    Custom(String),
}

#[derive(serde::Serialize)]
pub struct ApiError {
    pub code: u16,
    pub message: String,
}


impl axum::response::IntoResponse for AppError {
    fn into_response(self) -> axum::response::Response {
        (
            axum::http::StatusCode::INTERNAL_SERVER_ERROR,
            axum::Json(ApiError {
                code: 500,
                message: self.to_string(),
            }),
        )
            .into_response()
    }
}

IntoResponseの実装を準備しておくことで、handler実装のResultに直接 thiserror実装を渡すことができるようになり、実装を進めるのが楽になる。

それだけではなく、レスポンスに渡すエラー詳細のマスクを行ったり、エラーの詳細をAPIのレスポンスに含めないようにすること、あるいはClient側でのエラー切り分けが実現できるような基盤を整えることができる。

utoipaApiErrorの連携をしたい場合は、こちらを参照。


関連タグを探す