r2_data2/
error.rs

1use axum::{
2    Json,
3    http::StatusCode,
4    response::{IntoResponse, Response},
5};
6use serde_json::json;
7use thiserror::Error;
8use tracing::warn;
9
10#[derive(Error, Debug, Clone)]
11pub enum AuthError {
12    #[error("Invalid token: {0}")]
13    InvalidToken(String),
14
15    #[error("Missing credentials")]
16    MissingCredentials,
17
18    #[error("Token creation error")]
19    TokenCreation,
20
21    #[error("Internal server error (auth)")]
22    InternalError,
23}
24
25// General AppError Enum
26#[derive(Error, Debug)]
27pub enum AppError {
28    #[error(transparent)]
29    Auth(#[from] AuthError),
30
31    #[error("Database error: {0}")]
32    Database(#[from] sqlx::Error),
33
34    #[error("Unsupported database type: {0}")]
35    UnsupportedDatabaseType(String),
36
37    #[error("Configuration error: {0}")]
38    Config(#[from] config::ConfigError),
39
40    #[error("Not found: {0}")]
41    NotFound(String),
42
43    #[error("Not implemented: {0}")]
44    NotImplemented(String),
45
46    #[error("Bad request: {0}")]
47    BadRequest(String),
48
49    #[error("SQL parsing error: {0}")]
50    SqlParsingError(String),
51
52    #[error("Invalid query result: {0}")]
53    InvalidQueryResult(String),
54
55    #[error("AI error: {0}")]
56    AiError(String),
57}
58
59impl IntoResponse for AuthError {
60    fn into_response(self) -> Response {
61        let (status, error_message) = match self {
62            AuthError::InvalidToken(msg) => {
63                (StatusCode::UNAUTHORIZED, format!("Invalid Token: {}", msg))
64            }
65            AuthError::MissingCredentials => {
66                (StatusCode::UNAUTHORIZED, "Missing Credentials".to_string())
67            }
68            AuthError::TokenCreation => (
69                StatusCode::INTERNAL_SERVER_ERROR,
70                "Internal error".to_string(),
71            ),
72            AuthError::InternalError => (
73                StatusCode::INTERNAL_SERVER_ERROR,
74                "Internal error".to_string(),
75            ),
76        };
77
78        let body = Json(json!({ "error": error_message }));
79        (status, body).into_response()
80    }
81}
82
83impl IntoResponse for AppError {
84    fn into_response(self) -> Response {
85        let (status, error_message) = match self {
86            AppError::Auth(auth_error) => {
87                // Reuse AuthError's IntoResponse implementation detail logic
88                return auth_error.into_response();
89            }
90            AppError::Database(db_err) => {
91                // Log the detailed DB error for internal review
92                tracing::error!("Database error: {}", db_err);
93                // Provide a generic message to the client
94                (
95                    StatusCode::INTERNAL_SERVER_ERROR,
96                    "Internal database error".to_string(),
97                )
98            }
99            AppError::UnsupportedDatabaseType(db_type) => (
100                StatusCode::BAD_REQUEST,
101                format!("Unsupported database type: {}", db_type),
102            ),
103            AppError::Config(config_err) => {
104                tracing::error!("Configuration error: {}", config_err);
105                (
106                    StatusCode::INTERNAL_SERVER_ERROR,
107                    "Server configuration error".to_string(),
108                )
109            }
110            AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
111            AppError::NotImplemented(msg) => (StatusCode::NOT_IMPLEMENTED, msg),
112            AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
113            AppError::SqlParsingError(msg) => (StatusCode::BAD_REQUEST, msg),
114            AppError::InvalidQueryResult(msg) => {
115                warn!("Invalid query result: {}", msg);
116                (
117                    StatusCode::INTERNAL_SERVER_ERROR,
118                    "Invalid query result".to_string(),
119                )
120            }
121            AppError::AiError(msg) => {
122                tracing::error!("AI generation error: {}", msg);
123                (
124                    StatusCode::INTERNAL_SERVER_ERROR,
125                    format!("AI generation failed: {}", msg),
126                )
127            }
128        };
129
130        let body = Json(json!({ "error": error_message }));
131        (status, body).into_response()
132    }
133}