use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, thiserror::Error)]
pub enum RainError {
#[error("HTTP error: {0}")]
HttpError(#[from] reqwest::Error),
#[error("API error (status {status}): {response}")]
ApiError {
status: u16,
response: Box<ApiErrorResponse>,
},
#[error("Authentication error: {0}")]
AuthError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Deserialization error: {0}")]
DeserializationError(#[from] serde_json::Error),
#[error("Error: {0}")]
Other(#[from] anyhow::Error),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiErrorResponse {
pub message: Option<String>,
pub code: Option<String>,
pub details: Option<serde_json::Value>,
}
impl ApiErrorResponse {
pub fn new(message: String) -> Self {
Self {
message: Some(message),
code: None,
details: None,
}
}
pub fn with_code(message: String, code: String) -> Self {
Self {
message: Some(message),
code: Some(code),
details: None,
}
}
}
impl fmt::Display for ApiErrorResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref message) = self.message {
write!(f, "{message}")?;
} else if let Some(ref code) = self.code {
write!(f, "{code}")?;
} else {
write!(f, "API error")?;
}
Ok(())
}
}
impl std::error::Error for ApiErrorResponse {}
impl From<ApiErrorResponse> for RainError {
fn from(err: ApiErrorResponse) -> Self {
RainError::ApiError {
status: 500,
response: Box::new(err),
}
}
}
pub type Result<T> = std::result::Result<T, RainError>;
impl From<serde_urlencoded::ser::Error> for RainError {
fn from(err: serde_urlencoded::ser::Error) -> Self {
RainError::ValidationError(format!("URL encoding error: {err}"))
}
}