use axum::response::IntoResponse; use reqwest::StatusCode; /// Central error type for infrastructure-layer failures. /// /// Each variant maps to an appropriate HTTP status code when converted /// into an Axum response. #[derive(thiserror::Error, Debug)] pub enum Error { #[error("{0}")] StateError(String), #[error("database error: {0}")] DatabaseError(String), #[error("configuration error: {0}")] ConfigError(String), #[error("IoError: {0}")] IoError(#[from] std::io::Error), } impl From for Error { fn from(err: mongodb::error::Error) -> Self { Self::DatabaseError(err.to_string()) } } impl IntoResponse for Error { fn into_response(self) -> axum::response::Response { let msg = self.to_string(); tracing::error!("Converting Error to Response: {msg}"); match self { Self::StateError(e) | Self::ConfigError(e) => { (StatusCode::INTERNAL_SERVER_ERROR, e).into_response() } Self::DatabaseError(e) => (StatusCode::SERVICE_UNAVAILABLE, e).into_response(), Self::IoError(_) => { (StatusCode::INTERNAL_SERVER_ERROR, "Unknown error").into_response() } } } } #[cfg(test)] mod tests { use super::*; use axum::response::IntoResponse; use pretty_assertions::assert_eq; #[test] fn state_error_display() { let err = Error::StateError("bad state".into()); assert_eq!(err.to_string(), "bad state"); } #[test] fn database_error_display() { let err = Error::DatabaseError("connection lost".into()); assert_eq!(err.to_string(), "database error: connection lost"); } #[test] fn config_error_display() { let err = Error::ConfigError("missing var".into()); assert_eq!(err.to_string(), "configuration error: missing var"); } #[test] fn state_error_into_response_500() { let resp = Error::StateError("oops".into()).into_response(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } #[test] fn database_error_into_response_503() { let resp = Error::DatabaseError("down".into()).into_response(); assert_eq!(resp.status(), StatusCode::SERVICE_UNAVAILABLE); } #[test] fn config_error_into_response_500() { let resp = Error::ConfigError("bad cfg".into()).into_response(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } #[test] fn io_error_into_response_500() { let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "not found"); let resp = Error::IoError(io_err).into_response(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } }