axum_bootstrap/
error.rs

1use anyhow::anyhow;
2use std::fmt::Display;
3
4use axum::response::{IntoResponse, Response};
5use hyper::StatusCode;
6
7// Make our own error that wraps `anyhow::Error`.
8#[derive(Debug)]
9pub struct AppError(anyhow::Error);
10
11impl Display for AppError {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        self.0.fmt(f)
14    }
15}
16// Tell axum how to convert `AppError` into a response.
17impl IntoResponse for AppError {
18    fn into_response(self) -> Response {
19        let err = self.0;
20        // Because `TraceLayer` wraps each request in a span that contains the request
21        // method, uri, etc we don't need to include those details here
22        tracing::error!(%err, "error");
23        (StatusCode::INTERNAL_SERVER_ERROR, format!("ERROR: {}", &err)).into_response()
24    }
25}
26
27// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
28// `Result<_, AppError>`. That way you don't need to do that manually.
29impl<E> From<E> for AppError
30where
31    E: Into<anyhow::Error>,
32{
33    fn from(err: E) -> Self {
34        Self(err.into())
35    }
36}
37
38impl AppError {
39    pub fn new<T: std::error::Error + Send + Sync + 'static>(err: T) -> Self {
40        Self(anyhow!(err))
41    }
42}