slack status without the slack
status.zzstoatzz.io/
quickslice
1use actix_web::{HttpResponse, error::ResponseError, http::StatusCode};
2use std::fmt;
3
4#[derive(Debug)]
5pub enum AppError {
6 InternalError(String),
7 DatabaseError(String),
8 AuthenticationError(String),
9 #[allow(dead_code)] // Keep for potential future use
10 ValidationError(String),
11 #[allow(dead_code)] // Keep for potential future use
12 NotFound(String),
13 RateLimitExceeded,
14}
15
16impl fmt::Display for AppError {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 match self {
19 AppError::InternalError(msg) => write!(f, "Internal server error: {}", msg),
20 AppError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
21 AppError::AuthenticationError(msg) => write!(f, "Authentication error: {}", msg),
22 AppError::ValidationError(msg) => write!(f, "Validation error: {}", msg),
23 AppError::NotFound(msg) => write!(f, "Not found: {}", msg),
24 AppError::RateLimitExceeded => write!(f, "Rate limit exceeded"),
25 }
26 }
27}
28
29impl ResponseError for AppError {
30 fn error_response(&self) -> HttpResponse {
31 let (status_code, error_message) = match self {
32 AppError::InternalError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
33 AppError::DatabaseError(_) => (
34 StatusCode::INTERNAL_SERVER_ERROR,
35 "Database error occurred".to_string(),
36 ),
37 AppError::AuthenticationError(msg) => (StatusCode::UNAUTHORIZED, msg.clone()),
38 AppError::ValidationError(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
39 AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
40 AppError::RateLimitExceeded => (
41 StatusCode::TOO_MANY_REQUESTS,
42 "Rate limit exceeded. Please try again later.".to_string(),
43 ),
44 };
45
46 HttpResponse::build(status_code).body(format!(
47 "Error {}: {}",
48 status_code.as_u16(),
49 error_message
50 ))
51 }
52
53 fn status_code(&self) -> StatusCode {
54 match self {
55 AppError::InternalError(_) | AppError::DatabaseError(_) => {
56 StatusCode::INTERNAL_SERVER_ERROR
57 }
58 AppError::AuthenticationError(_) => StatusCode::UNAUTHORIZED,
59 AppError::ValidationError(_) => StatusCode::BAD_REQUEST,
60 AppError::NotFound(_) => StatusCode::NOT_FOUND,
61 AppError::RateLimitExceeded => StatusCode::TOO_MANY_REQUESTS,
62 }
63 }
64}
65
66// Conversion helpers
67impl From<async_sqlite::Error> for AppError {
68 fn from(err: async_sqlite::Error) -> Self {
69 AppError::DatabaseError(err.to_string())
70 }
71}
72
73impl From<serde_json::Error> for AppError {
74 fn from(err: serde_json::Error) -> Self {
75 AppError::InternalError(err.to_string())
76 }
77}
78
79// Helper function to wrap results - removed as unused
80// If needed in the future, use: result.map_err(|e| ErrorInternalServerError(e))
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_error_display() {
88 let err = AppError::ValidationError("Invalid input".to_string());
89 assert_eq!(err.to_string(), "Validation error: Invalid input");
90
91 let err = AppError::RateLimitExceeded;
92 assert_eq!(err.to_string(), "Rate limit exceeded");
93 }
94
95 #[test]
96 fn test_error_status_codes() {
97 assert_eq!(
98 AppError::InternalError("test".to_string()).status_code(),
99 StatusCode::INTERNAL_SERVER_ERROR
100 );
101 assert_eq!(
102 AppError::ValidationError("test".to_string()).status_code(),
103 StatusCode::BAD_REQUEST
104 );
105 assert_eq!(
106 AppError::AuthenticationError("test".to_string()).status_code(),
107 StatusCode::UNAUTHORIZED
108 );
109 assert_eq!(
110 AppError::NotFound("test".to_string()).status_code(),
111 StatusCode::NOT_FOUND
112 );
113 assert_eq!(
114 AppError::RateLimitExceeded.status_code(),
115 StatusCode::TOO_MANY_REQUESTS
116 );
117 }
118}