polyte_core/
error.rs

1use thiserror::Error;
2
3/// Core API error types shared across Polyte clients
4#[derive(Error, Debug)]
5pub enum ApiError {
6    /// HTTP request failed
7    #[error("API error: {status} - {message}")]
8    Api { status: u16, message: String },
9
10    /// Authentication failed (401/403)
11    #[error("Authentication failed: {0}")]
12    Authentication(String),
13
14    /// Request validation failed (400)
15    #[error("Validation error: {0}")]
16    Validation(String),
17
18    /// Rate limit exceeded (429)
19    #[error("Rate limit exceeded")]
20    RateLimit,
21
22    /// Request timeout
23    #[error("Request timeout")]
24    Timeout,
25
26    /// Network error
27    #[error("Network error: {0}")]
28    Network(#[from] reqwest::Error),
29
30    /// JSON serialization/deserialization error
31    #[error("Serialization error: {0}")]
32    Serialization(#[from] serde_json::Error),
33
34    /// URL parsing error
35    #[error("URL error: {0}")]
36    Url(#[from] url::ParseError),
37}
38
39impl ApiError {
40    /// Create error from HTTP response
41    pub async fn from_response(response: reqwest::Response) -> Self {
42        let status = response.status().as_u16();
43
44        let message = response
45            .json::<serde_json::Value>()
46            .await
47            .ok()
48            .and_then(|v| {
49                v.get("error")
50                    .or(v.get("message"))
51                    .and_then(|m| m.as_str())
52                    .map(String::from)
53            })
54            .unwrap_or_else(|| "Unknown error".to_string());
55
56        match status {
57            401 | 403 => Self::Authentication(message),
58            400 => Self::Validation(message),
59            429 => Self::RateLimit,
60            408 => Self::Timeout,
61            _ => Self::Api { status, message },
62        }
63    }
64}