1use crate::models::ErrorResponse;
6use thiserror::Error;
7
8#[derive(Error, Debug)]
10pub enum TypecastError {
11 #[error("Bad Request - {detail}")]
13 BadRequest { detail: String },
14
15 #[error("Unauthorized - Invalid or missing API key")]
17 Unauthorized { detail: String },
18
19 #[error("Payment Required - Insufficient credits")]
21 PaymentRequired { detail: String },
22
23 #[error("Forbidden - Access denied")]
25 Forbidden { detail: String },
26
27 #[error("Not Found - {detail}")]
29 NotFound { detail: String },
30
31 #[error("Validation Error - {detail}")]
33 ValidationError { detail: String },
34
35 #[error("Too Many Requests - Rate limit exceeded")]
37 RateLimited { detail: String },
38
39 #[error("Internal Server Error - {detail}")]
41 ServerError { detail: String },
42
43 #[error("HTTP error: {0}")]
45 HttpError(#[from] reqwest::Error),
46
47 #[error("JSON error: {0}")]
49 JsonError(#[from] serde_json::Error),
50
51 #[error("API error (status {status_code}): {detail}")]
53 Unknown { status_code: u16, detail: String },
54}
55
56impl TypecastError {
57 pub fn from_response(status_code: u16, error_response: Option<ErrorResponse>) -> Self {
59 let detail = error_response
60 .map(|e| e.detail)
61 .unwrap_or_else(|| "Unknown error".to_string());
62
63 match status_code {
64 400 => TypecastError::BadRequest { detail },
65 401 => TypecastError::Unauthorized { detail },
66 402 => TypecastError::PaymentRequired { detail },
67 403 => TypecastError::Forbidden { detail },
68 404 => TypecastError::NotFound { detail },
69 422 => TypecastError::ValidationError { detail },
70 429 => TypecastError::RateLimited { detail },
71 500..=599 => TypecastError::ServerError { detail },
72 _ => TypecastError::Unknown { status_code, detail },
73 }
74 }
75
76 pub fn is_bad_request(&self) -> bool {
78 matches!(self, TypecastError::BadRequest { .. })
79 }
80
81 pub fn is_unauthorized(&self) -> bool {
83 matches!(self, TypecastError::Unauthorized { .. })
84 }
85
86 pub fn is_payment_required(&self) -> bool {
88 matches!(self, TypecastError::PaymentRequired { .. })
89 }
90
91 pub fn is_forbidden(&self) -> bool {
93 matches!(self, TypecastError::Forbidden { .. })
94 }
95
96 pub fn is_not_found(&self) -> bool {
98 matches!(self, TypecastError::NotFound { .. })
99 }
100
101 pub fn is_validation_error(&self) -> bool {
103 matches!(self, TypecastError::ValidationError { .. })
104 }
105
106 pub fn is_rate_limited(&self) -> bool {
108 matches!(self, TypecastError::RateLimited { .. })
109 }
110
111 pub fn is_server_error(&self) -> bool {
113 matches!(self, TypecastError::ServerError { .. })
114 }
115
116 pub fn status_code(&self) -> Option<u16> {
118 match self {
119 TypecastError::BadRequest { .. } => Some(400),
120 TypecastError::Unauthorized { .. } => Some(401),
121 TypecastError::PaymentRequired { .. } => Some(402),
122 TypecastError::Forbidden { .. } => Some(403),
123 TypecastError::NotFound { .. } => Some(404),
124 TypecastError::ValidationError { .. } => Some(422),
125 TypecastError::RateLimited { .. } => Some(429),
126 TypecastError::ServerError { .. } => Some(500),
127 TypecastError::Unknown { status_code, .. } => Some(*status_code),
128 _ => None,
129 }
130 }
131}
132
133pub type Result<T> = std::result::Result<T, TypecastError>;