backstage_client/
error.rs

1use reqwest::Error as ReqwestError;
2use serde_json::Error as SerdeJsonError;
3use std::fmt;
4
5/// Error types that can occur when using the Backstage client.
6#[derive(Debug)]
7pub enum ClientError {
8    /// HTTP request failed
9    Http(ReqwestError),
10    /// JSON serialization/deserialization failed
11    Json(SerdeJsonError),
12    /// Invalid URL provided
13    InvalidUrl(String),
14    /// Authentication failed
15    Authentication(String),
16    /// API returned an error response
17    ApiError { status: u16, message: String },
18    /// Invalid filter parameters
19    InvalidFilter(String),
20    /// Network timeout
21    Timeout,
22    /// Generic client error
23    Other(String),
24}
25
26impl fmt::Display for ClientError {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            ClientError::Http(err) => write!(f, "HTTP request failed: {}", err),
30            ClientError::Json(err) => write!(f, "JSON parsing failed: {}", err),
31            ClientError::InvalidUrl(url) => write!(f, "Invalid URL: {}", url),
32            ClientError::Authentication(msg) => write!(f, "Authentication failed: {}", msg),
33            ClientError::ApiError { status, message } => {
34                write!(f, "API error (status {}): {}", status, message)
35            }
36            ClientError::InvalidFilter(msg) => write!(f, "Invalid filter: {}", msg),
37            ClientError::Timeout => write!(f, "Request timed out"),
38            ClientError::Other(msg) => write!(f, "Client error: {}", msg),
39        }
40    }
41}
42
43impl std::error::Error for ClientError {
44    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
45        match self {
46            ClientError::Http(err) => Some(err),
47            ClientError::Json(err) => Some(err),
48            _ => None,
49        }
50    }
51}
52
53impl From<ReqwestError> for ClientError {
54    fn from(err: ReqwestError) -> ClientError {
55        if err.is_timeout() {
56            ClientError::Timeout
57        } else if err.is_status() {
58            if let Some(status) = err.status() {
59                ClientError::ApiError {
60                    status: status.as_u16(),
61                    message: err.to_string(),
62                }
63            } else {
64                ClientError::Http(err)
65            }
66        } else {
67            ClientError::Http(err)
68        }
69    }
70}
71
72impl From<SerdeJsonError> for ClientError {
73    fn from(err: SerdeJsonError) -> ClientError {
74        ClientError::Json(err)
75    }
76}
77
78impl From<url::ParseError> for ClientError {
79    fn from(err: url::ParseError) -> ClientError {
80        ClientError::InvalidUrl(err.to_string())
81    }
82}
83
84/// Result type alias for client operations
85pub type Result<T> = std::result::Result<T, ClientError>;