use std::collections::HashMap;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("Authentication failed: {message}")]
Authentication {
message: String,
code: Option<String>,
},
#[error("Bad request: {message}")]
BadRequest {
message: String,
code: Option<String>,
},
#[error("Not found: {message}")]
NotFound {
message: String,
code: Option<String>,
},
#[error("Validation failed: {message}")]
Validation {
message: String,
errors: HashMap<String, Vec<String>>,
code: Option<String>,
},
#[error("Rate limit exceeded: {message}")]
RateLimit {
message: String,
retry_after: Option<u64>,
code: Option<String>,
},
#[error("Server error: {message}")]
Server {
message: String,
status_code: u16,
code: Option<String>,
},
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("Invalid header: {0}")]
InvalidHeader(String),
#[error("Request timeout")]
Timeout,
}
impl Error {
pub fn code(&self) -> Option<&str> {
match self {
Error::Authentication { code, .. } => code.as_deref(),
Error::BadRequest { code, .. } => code.as_deref(),
Error::NotFound { code, .. } => code.as_deref(),
Error::Validation { code, .. } => code.as_deref(),
Error::RateLimit { code, .. } => code.as_deref(),
Error::Server { code, .. } => code.as_deref(),
_ => None,
}
}
pub fn status_code(&self) -> Option<u16> {
match self {
Error::Authentication { .. } => Some(401),
Error::BadRequest { .. } => Some(400),
Error::NotFound { .. } => Some(404),
Error::Validation { .. } => Some(422),
Error::RateLimit { .. } => Some(429),
Error::Server { status_code, .. } => Some(*status_code),
_ => None,
}
}
pub fn retry_after(&self) -> Option<u64> {
match self {
Error::RateLimit { retry_after, .. } => *retry_after,
_ => None,
}
}
pub fn validation_errors(&self) -> Option<&HashMap<String, Vec<String>>> {
match self {
Error::Validation { errors, .. } => Some(errors),
_ => None,
}
}
pub fn is_retryable(&self) -> bool {
match self {
Error::Server { status_code, .. } => {
matches!(status_code, 500 | 502 | 503 | 504)
}
Error::Timeout => true,
Error::Http(e) => e.is_connect() || e.is_timeout(),
_ => false,
}
}
}
pub type Result<T> = std::result::Result<T, Error>;