1use soap_client::SoapError;
2use thiserror::Error;
3
4#[derive(Debug, Error)]
10pub enum ApiError {
11 #[error("Network error: {0}")]
17 NetworkError(String),
18
19 #[error("Parse error: {0}")]
25 ParseError(String),
26
27 #[error("SOAP fault: error code {0}")]
32 SoapFault(u16),
33
34 #[error("Invalid parameter: {0}")]
39 InvalidParameter(String),
40
41 #[error("Subscription error: {0}")]
46 SubscriptionError(String),
47
48 #[error("Device error: {0}")]
53 DeviceError(String),
54}
55
56impl ApiError {
57 pub fn subscription_expired() -> Self {
59 Self::SubscriptionError("Subscription expired".to_string())
60 }
61}
62
63pub type Result<T> = std::result::Result<T, ApiError>;
65
66impl From<SoapError> for ApiError {
68 fn from(error: SoapError) -> Self {
69 match error {
70 SoapError::Network(msg) => ApiError::NetworkError(msg),
71 SoapError::Parse(msg) => ApiError::ParseError(msg),
72 SoapError::Fault(code) => ApiError::SoapFault(code),
73 }
74 }
75}
76
77impl From<crate::operation::ValidationError> for ApiError {
79 fn from(validation_error: crate::operation::ValidationError) -> Self {
80 match validation_error {
81 crate::operation::ValidationError::InvalidValue {
82 parameter,
83 value,
84 reason,
85 } => ApiError::InvalidParameter(format!(
86 "Invalid value '{value}' for parameter '{parameter}': {reason}"
87 )),
88 crate::operation::ValidationError::RangeError {
89 parameter,
90 value,
91 min,
92 max,
93 } => ApiError::InvalidParameter(format!(
94 "Parameter '{parameter}' value {value} is out of range [{min}, {max}]"
95 )),
96 crate::operation::ValidationError::Custom { parameter, message } => {
97 ApiError::InvalidParameter(format!("Parameter '{parameter}': {message}"))
98 }
99 crate::operation::ValidationError::MissingParameter { parameter } => {
100 ApiError::InvalidParameter(format!("Required parameter '{parameter}' is missing"))
101 }
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_subscription_expired() {
112 let error = ApiError::subscription_expired();
113 assert!(matches!(error, ApiError::SubscriptionError(_)));
114 let error_str = format!("{error}");
115 assert!(error_str.contains("expired"));
116 }
117
118 #[test]
119 fn test_soap_error_conversion() {
120 let soap_error = SoapError::Network("connection timeout".to_string());
121 let api_error: ApiError = soap_error.into();
122 assert!(matches!(api_error, ApiError::NetworkError(_)));
123
124 let soap_error = SoapError::Parse("invalid XML".to_string());
125 let api_error: ApiError = soap_error.into();
126 assert!(matches!(api_error, ApiError::ParseError(_)));
127
128 let soap_error = SoapError::Fault(500);
129 let api_error: ApiError = soap_error.into();
130 assert!(matches!(api_error, ApiError::SoapFault(500)));
131 }
132
133 #[test]
134 fn test_error_display() {
135 let network_err = ApiError::NetworkError("connection failed".to_string());
136 assert_eq!(format!("{network_err}"), "Network error: connection failed");
137
138 let parse_err = ApiError::ParseError("invalid XML".to_string());
139 assert_eq!(format!("{parse_err}"), "Parse error: invalid XML");
140
141 let soap_fault = ApiError::SoapFault(500);
142 assert_eq!(format!("{soap_fault}"), "SOAP fault: error code 500");
143 }
144}