Axum

Axumエラーハンドリングの基礎と実装方法

ⓘ本ページはプロモーションが含まれています

スポンサードリンク

Axumにおけるエラーハンドリングの基礎概念

Axumでのエラーハンドリングは、「tower::Service」のError型とInfallibleトレイトの関係性に深く関わっています。Webサーバーが予期せぬエラーを返さないためには、フレームワークレベルでエラータイプを統一的に管理する仕組みが必要です。このセクションでは、その基礎的な流れと設計思想を解説します。

tower::ServiceのError型とInfallibleの役割

Axumは、Rustのtowerライブラリに依存して非同期処理を実装しています。これにより、ハンドラ関数内で発生するエラーが「tower::Service::Error」として統一的に扱われます。

Infallibleトレイトとは

  • Rust標準で定義されたstd::convert::Infallibleトレイトは、「実行時にパニックを起こさない型」を表します。
  • これは、Rustの安全性担保に深く関係しており、Result<T, Infallible>という型定義は「成功するか永続的に失敗しない」ことを意味します(例: Ok(())のみが存在)。
  • towerライブラリでは、Serviceトレイトのエラー戻り値としてInfallibleをデフォルトで使用しており、これによりサーバーのクラッシュを防ぎます。
項目 内容 補足
tower::Service::Error サービスが返す可能性のあるエラー型 多くはBox<dyn std::error::Error + Send + Sync>など
Infallible ネットワーク通信など、「絶対にエラーにならない」場面で使用 Rust標準トレイト

エラー処理のフロー概要

Axumでは、ハンドラ関数内で発生したエラーが自動的にIntoResponseトレイトを実装する型に変換されます。この流れには以下のようなステップがあります。

  1. ハンドラ内でエラーが発生Result<T, E>型として返される
  2. HandleErrorマクロでエラー型を指定 → カスタムレスポンスを設定
  3. AxumがIntoResponseトレイトを使ってHTTP応答に変換

注意点: 未処理のエラーは、サーバー側でクラッシュする可能性があります。必ずHandleErrorやカスタム型で捕まえる必要があります。


HandleErrorマクロによるエラーレスポンスカスタマイズ

AxumのHandleErrorマクロは、特定のエラー型に応じて自動的にカスタムなHTTPレスポンスを生成する仕組みです。これにより、一貫したエラー表現を実現できます。

基本構文と動作原理

HandleErrorマクロの基本的な使用例は以下の通りです。

このコードでは、CustomErrorが発生した場合に自動的に404 Not Foundレスポンスを返すようにしています。

  • ポイント: HandleErrorは、impl IntoResponse for Eが実装された型に対してのみ効果を持ちます。
  • 理由: Axumは、エラーをIntoResponseトレイトを使ってHTTP応答に変換する必要があります。

複数のエラー型への対応方法

複数のエラー型を扱う場合、HandleErrorマクロ内でパターンマッチを行い、それぞれに応じたレスポンスを作成します。

例として、sqlx::Errorや独自のエラー型を扱う方法が確認できます。このように分岐処理することで、ユーザーに適切なフィードバックを提供できます。


カスタムエラー型の定義とanyhow::Errorの活用

ビジネスロジックに応じたカスタムエラー型は、「共通のインターフェースでエラーレスポンスを作成しやすくなる」という利点があります。anyhow::Errorを使うことで、エラー診断情報を柔軟に保持可能です。

エラータイプの設計方針

カスタムエラー型を定義する際は以下の2つのポイントが重要です。

  1. エラーの種類と状態を明確に分ける(例: データベースエラー、入力不正など)
  2. anyhow::Errorと連携させる(診断情報を保持しやすい)

anyhow::Errorは、エラーの原因をトレースできるため、デバッグに役立ちます。カスタム型でラップすることで、診断情報も一緒に伝えることができます。


IntoResponseトレイトの実装と独自型設計

Axumでは、ハンドラ関数が返す値はIntoResponseトレイトを実装する必要があります。このトレイトを独自型に適用することで、カスタムなHTTP応答形式を作成できます。

標準型への変換ロジック

IntoResponseトレイトの実装例(基本的な構造)は以下の通りです。

  • statusフィールドは、HTTPステータスコードを指定
  • messageフィールドは、エラーメッセージを保持

ステータスコードとボディのカスタマイズ

カスタム型に応じてステータスコードやJSONボディを変更する例です。

エラー種類 ステータスコード レスポンスボディ
NotFound 404 {"code": 404, "message": "Resource not found"}
InvalidInput 400 {"code": 400, "message": "Invalid data format"}

注意事項: JSON形式で返す場合、serde_jsonライブラリが必須です。エラーメッセージには具体的な情報を含めることが重要です。


データベースクレートとの連携時におけるエラーハンドリング

SQLクエリなどで発生したエラーは、Axumのカスタムエラー型に変換することで統一的なレスポンスを実現できます。特にsqlxなどのDBクレートと組み合わせる場合に注意が必要です。

sqlxのError型とAxumの統合

sqlx::Errorは、IntoResponseトレイトを実装していないため、独自のカスタムエラー型にラップする必要があります。以下がその例です。

上記コードでは、sqlx::ErrorDbErrorに変換し、Axumのエラーレスポンスに統合しています。


サブリクエスト時のエラー伝搬

サブリクエスト(例: サードパーティAPIへのリクエスト)が失敗した場合、エラーを適切にキャッチする必要があります。HandleErrorマクロと組み合わせて以下のように処理できます。


まとめ

  • Axumでのエラーハンドリングは、tower::Service::ErrorInfallibleの理解が不可欠
  • HandleErrorマクロを使って、複数のエラー型に応じたレスポンスを設定
  • anyhow::Errorをラップしたカスタム型で診断情報を保持
  • IntoResponseトレイトを実装することで、独自型をHTTP応答に変換
  • DBクレートと連携する際には、エラー型を統一的に処理

このように設計を行うことで、Rust開発者はAxumの強力なエラーハンドリング機能を最大限活用できます。記事で解説した方法を基に、自身のAxumプロジェクトにおけるエラーハンドリング構造を再設計してみてください。


スポンサードリンク

-Axum