1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum ApiError {
5 #[error("BadRequestError: Bad request - {{message}}")]
6 BadRequestError {
7 message: String,
8 field: Option<String>,
9 details: Option<String>,
10 },
11 #[error("UnauthorizedError: Authentication failed - {{message}}")]
12 UnauthorizedError {
13 message: String,
14 auth_type: Option<String>,
15 },
16 #[error("NotFoundError: Resource not found - {{message}}")]
17 NotFoundError {
18 message: String,
19 resource_id: Option<String>,
20 resource_type: Option<String>,
21 },
22 #[error("RequestTimeoutError: {{message}}")]
23 RequestTimeoutError { message: String },
24 #[error("TooManyRequestsError: Rate limit exceeded - {{message}}")]
25 TooManyRequestsError {
26 message: String,
27 retry_after_seconds: Option<u64>,
28 limit_type: Option<String>,
29 },
30 #[error("InternalServerError: Internal server error - {{message}}")]
31 InternalServerError {
32 message: String,
33 error_id: Option<String>,
34 },
35 #[error("ContentTooLargeError: {{message}}")]
36 ContentTooLargeError { message: String },
37 #[error("InsufficientStorageError: {{message}}")]
38 InsufficientStorageError { message: String },
39 #[error("HTTP error {status}: {message}")]
40 Http { status: u16, message: String },
41 #[error("Network error: {0}")]
42 Network(reqwest::Error),
43 #[error("Serialization error: {0}")]
44 Serialization(serde_json::Error),
45 #[error("Configuration error: {0}")]
46 Configuration(String),
47 #[error("Invalid header value")]
48 InvalidHeader,
49 #[error("Could not clone request for retry")]
50 RequestClone,
51 #[error("SSE stream terminated")]
52 StreamTerminated,
53 #[error("SSE parse error: {0}")]
54 SseParseError(String),
55}
56
57impl ApiError {
58 pub fn from_response(status_code: u16, body: Option<&str>) -> Self {
59 match status_code {
60 400 => {
61 if let Some(body_str) = body {
63 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
64 return Self::BadRequestError {
65 message: parsed
66 .get("message")
67 .and_then(|v| v.as_str())
68 .unwrap_or("Unknown error")
69 .to_string(),
70 field: parsed
71 .get("field")
72 .and_then(|v| v.as_str().map(|s| s.to_string())),
73 details: parsed
74 .get("details")
75 .and_then(|v| v.as_str().map(|s| s.to_string())),
76 };
77 }
78 }
79 return Self::BadRequestError {
80 message: body.unwrap_or("Unknown error").to_string(),
81 field: None,
82 details: None,
83 };
84 }
85 401 => {
86 if let Some(body_str) = body {
88 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
89 return Self::UnauthorizedError {
90 message: parsed
91 .get("message")
92 .and_then(|v| v.as_str())
93 .unwrap_or("Unknown error")
94 .to_string(),
95 auth_type: parsed
96 .get("auth_type")
97 .and_then(|v| v.as_str().map(|s| s.to_string())),
98 };
99 }
100 }
101 return Self::UnauthorizedError {
102 message: body.unwrap_or("Unknown error").to_string(),
103 auth_type: None,
104 };
105 }
106 404 => {
107 if let Some(body_str) = body {
109 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
110 return Self::NotFoundError {
111 message: parsed
112 .get("message")
113 .and_then(|v| v.as_str())
114 .unwrap_or("Unknown error")
115 .to_string(),
116 resource_id: parsed
117 .get("resource_id")
118 .and_then(|v| v.as_str().map(|s| s.to_string())),
119 resource_type: parsed
120 .get("resource_type")
121 .and_then(|v| v.as_str().map(|s| s.to_string())),
122 };
123 }
124 }
125 return Self::NotFoundError {
126 message: body.unwrap_or("Unknown error").to_string(),
127 resource_id: None,
128 resource_type: None,
129 };
130 }
131 408 => {
132 if let Some(body_str) = body {
134 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
135 return Self::RequestTimeoutError {
136 message: parsed
137 .get("message")
138 .and_then(|v| v.as_str())
139 .unwrap_or("Unknown error")
140 .to_string(),
141 };
142 }
143 }
144 return Self::RequestTimeoutError {
145 message: body.unwrap_or("Unknown error").to_string(),
146 };
147 }
148 429 => {
149 if let Some(body_str) = body {
151 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
152 return Self::TooManyRequestsError {
153 message: parsed
154 .get("message")
155 .and_then(|v| v.as_str())
156 .unwrap_or("Unknown error")
157 .to_string(),
158 retry_after_seconds: parsed
159 .get("retry_after_seconds")
160 .and_then(|v| v.as_u64()),
161 limit_type: parsed
162 .get("limit_type")
163 .and_then(|v| v.as_str().map(|s| s.to_string())),
164 };
165 }
166 }
167 return Self::TooManyRequestsError {
168 message: body.unwrap_or("Unknown error").to_string(),
169 retry_after_seconds: None,
170 limit_type: None,
171 };
172 }
173 500 => {
174 if let Some(body_str) = body {
176 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
177 return Self::InternalServerError {
178 message: parsed
179 .get("message")
180 .and_then(|v| v.as_str())
181 .unwrap_or("Unknown error")
182 .to_string(),
183 error_id: parsed
184 .get("error_id")
185 .and_then(|v| v.as_str().map(|s| s.to_string())),
186 };
187 }
188 }
189 return Self::InternalServerError {
190 message: body.unwrap_or("Unknown error").to_string(),
191 error_id: None,
192 };
193 }
194 413 => {
195 if let Some(body_str) = body {
197 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
198 return Self::ContentTooLargeError {
199 message: parsed
200 .get("message")
201 .and_then(|v| v.as_str())
202 .unwrap_or("Unknown error")
203 .to_string(),
204 };
205 }
206 }
207 return Self::ContentTooLargeError {
208 message: body.unwrap_or("Unknown error").to_string(),
209 };
210 }
211 507 => {
212 if let Some(body_str) = body {
214 if let Ok(parsed) = serde_json::from_str::<serde_json::Value>(body_str) {
215 return Self::InsufficientStorageError {
216 message: parsed
217 .get("message")
218 .and_then(|v| v.as_str())
219 .unwrap_or("Unknown error")
220 .to_string(),
221 };
222 }
223 }
224 return Self::InsufficientStorageError {
225 message: body.unwrap_or("Unknown error").to_string(),
226 };
227 }
228 _ => Self::Http {
229 status: status_code,
230 message: body.unwrap_or("Unknown error").to_string(),
231 },
232 }
233 }
234}