1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, thiserror::Error)]
8pub enum RainError {
9 #[error("HTTP error: {0}")]
11 HttpError(#[from] reqwest::Error),
12
13 #[error("API error: {0}")]
15 ApiError(Box<ApiErrorResponse>),
16
17 #[error("Authentication error: {0}")]
19 AuthError(String),
20
21 #[error("Validation error: {0}")]
23 ValidationError(String),
24
25 #[error("Deserialization error: {0}")]
27 DeserializationError(#[from] serde_json::Error),
28
29 #[error("Error: {0}")]
31 Other(#[from] anyhow::Error),
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ApiErrorResponse {
37 pub message: Option<String>,
39
40 pub code: Option<String>,
42
43 pub details: Option<serde_json::Value>,
45}
46
47impl fmt::Display for ApiErrorResponse {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 if let Some(ref message) = self.message {
50 write!(f, "{message}")?;
51 } else if let Some(ref code) = self.code {
52 write!(f, "{code}")?;
53 } else {
54 write!(f, "API error")?;
55 }
56 Ok(())
57 }
58}
59
60impl std::error::Error for ApiErrorResponse {}
61
62impl From<ApiErrorResponse> for RainError {
63 fn from(err: ApiErrorResponse) -> Self {
64 RainError::ApiError(Box::new(err))
65 }
66}
67
68pub type Result<T> = std::result::Result<T, RainError>;
70
71impl From<serde_urlencoded::ser::Error> for RainError {
72 fn from(err: serde_urlencoded::ser::Error) -> Self {
73 RainError::ValidationError(format!("URL encoding error: {err}"))
74 }
75}