use thiserror::Error;
#[derive(Error, Debug)]
pub enum ApiError {
#[error("API error: {status} - {message}")]
Api { status: u16, message: String },
#[error("Authentication failed: {0}")]
Authentication(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Rate limit exceeded")]
RateLimit,
#[error("Request timeout")]
Timeout,
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("URL error: {0}")]
Url(#[from] url::ParseError),
}
impl ApiError {
pub async fn from_response(response: reqwest::Response) -> Self {
let status = response.status().as_u16();
let message = response
.json::<serde_json::Value>()
.await
.ok()
.and_then(|v| {
v.get("error")
.or(v.get("message"))
.and_then(|m| m.as_str())
.map(String::from)
})
.unwrap_or_else(|| "Unknown error".to_string());
match status {
401 | 403 => Self::Authentication(message),
400 => Self::Validation(message),
429 => Self::RateLimit,
408 => Self::Timeout,
_ => Self::Api { status, message },
}
}
}