#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ApiError {
#[error("Unauthorized: invalid or missing API key")]
Unauthorized,
#[error("Rate limited — retry after {retry_after:?} seconds")]
RateLimit {
retry_after: Option<u64>,
},
#[error("Not found")]
NotFound,
#[error("Server error (HTTP {status})")]
ServerError {
status: u16,
},
#[error("Network error: {0}")]
NetworkError(#[from] reqwest::Error),
#[error("Failed to parse API response: {0}")]
ParseError(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unauthorized_display() {
let err = ApiError::Unauthorized;
assert_eq!(err.to_string(), "Unauthorized: invalid or missing API key");
}
#[test]
fn rate_limit_with_retry_after() {
let err = ApiError::RateLimit {
retry_after: Some(60),
};
assert!(err.to_string().contains("60"));
}
#[test]
fn rate_limit_without_retry_after() {
let err = ApiError::RateLimit { retry_after: None };
assert!(err.to_string().contains("None"));
}
#[test]
fn not_found_display() {
let err = ApiError::NotFound;
assert_eq!(err.to_string(), "Not found");
}
#[test]
fn server_error_display() {
let err = ApiError::ServerError { status: 503 };
assert!(err.to_string().contains("503"));
}
#[test]
fn parse_error_display() {
let err = ApiError::ParseError("missing field `id`".to_owned());
assert!(err.to_string().contains("missing field `id`"));
}
}