axum_dyn_error/
anyhow.rs

1//! Wrappers and extension traits for anyhow support
2
3use crate::{DynHttpError, HttpError, IntoHttpErrorResponse};
4use http::StatusCode;
5use std::{error::Error, fmt::Display};
6
7/// Wrapper around [anyhow::Error] allowing it to be used as a [HttpError],
8/// contains a [StatusCode] that will be used for the response.
9///
10/// If the `hide-anyhow` feature is enable errors from anyhow will contain a
11/// generic error message rather than the [Display] message
12#[derive(Debug)]
13pub struct AnyhowHttpError {
14    /// The anyhow error
15    error: anyhow::Error,
16    /// The response status code
17    status: StatusCode,
18}
19
20impl Error for AnyhowHttpError {
21    fn source(&self) -> Option<&(dyn Error + 'static)> {
22        self.error.source()
23    }
24}
25
26impl Display for AnyhowHttpError {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        Display::fmt(&self.error, f)
29    }
30}
31
32impl HttpError for AnyhowHttpError {
33    #[cfg(feature = "log")]
34    fn log(&self) {
35        // Anyhow errors contain a stacktrace so only the debug variant is used
36        log::error!("{:?}", self.error);
37    }
38
39    fn status(&self) -> StatusCode {
40        self.status
41    }
42
43    #[cfg(feature = "hide-anyhow")]
44    fn reason(&self) -> String {
45        // Anyhow errors use a generic message
46        "Server error".to_string()
47    }
48}
49
50/// Allow conversion from anyhow errors into [DynHttpError] by wrapping
51/// them with [AnyhowHttpError]
52impl<I> From<anyhow::Error> for DynHttpError<I>
53where
54    I: IntoHttpErrorResponse,
55{
56    fn from(value: anyhow::Error) -> Self {
57        value
58            // Give the error a default status
59            .status(StatusCode::INTERNAL_SERVER_ERROR)
60            // Convert into the dyn error type
61            .into()
62    }
63}
64
65/// Extension for adding a [StatusCode] to an anyhow error
66pub trait AnyhowStatusExt {
67    /// Add an additional status code to the anyhow error response
68    fn status(self, status: StatusCode) -> AnyhowHttpError;
69}
70
71impl AnyhowStatusExt for anyhow::Error {
72    fn status(self, status: StatusCode) -> AnyhowHttpError {
73        AnyhowHttpError {
74            error: self,
75            status,
76        }
77    }
78}