ztk_rust_sdk/
error.rs

1//! 错误类型定义
2//!
3//! 定义 SDK 中使用的错误类型,实现 std::error::Error trait
4
5use thiserror::Error;
6
7/// SDK 错误类型
8///
9/// 包含所有可能的错误情况:
10/// - 网络请求错误
11/// - API 业务错误
12/// - JSON 解析错误
13/// - 参数验证错误
14/// - URL 编码错误
15#[derive(Debug, Error)]
16pub enum ZtkError {
17    /// 网络请求错误
18    ///
19    /// 当 HTTP 请求失败时返回此错误
20    #[error("网络请求失败: {0}")]
21    Network(#[from] reqwest::Error),
22
23    /// API 业务错误
24    ///
25    /// 当 API 返回业务错误时返回此错误
26    #[error("API 错误 [{code}]: {message}")]
27    Api {
28        /// 错误码
29        code: i32,
30        /// 错误消息
31        message: String,
32        /// 子错误码
33        sub_code: Option<String>,
34        /// 子错误消息
35        sub_msg: Option<String>,
36    },
37
38    /// JSON 解析错误
39    ///
40    /// 当 JSON 反序列化失败时返回此错误
41    #[error("JSON 解析失败: {0}")]
42    Parse(#[from] serde_json::Error),
43
44    /// 参数验证错误
45    ///
46    /// 当请求参数验证失败时返回此错误
47    #[error("参数验证失败: {0}")]
48    Validation(String),
49
50    /// URL 编码错误
51    ///
52    /// 当 URL 编码失败时返回此错误
53    #[error("URL 编码失败: {0}")]
54    UrlEncode(String),
55}
56
57/// Result 类型别名
58///
59/// SDK 中所有返回 Result 的方法都使用此类型
60pub type ZtkResult<T> = Result<T, ZtkError>;
61
62impl ZtkError {
63    /// 创建 API 错误
64    ///
65    /// # Arguments
66    ///
67    /// * `code` - 错误码
68    /// * `message` - 错误消息
69    pub fn api(code: i32, message: impl Into<String>) -> Self {
70        ZtkError::Api {
71            code,
72            message: message.into(),
73            sub_code: None,
74            sub_msg: None,
75        }
76    }
77
78    /// 创建带子错误信息的 API 错误
79    ///
80    /// # Arguments
81    ///
82    /// * `code` - 错误码
83    /// * `message` - 错误消息
84    /// * `sub_code` - 子错误码
85    /// * `sub_msg` - 子错误消息
86    pub fn api_with_sub(
87        code: i32,
88        message: impl Into<String>,
89        sub_code: Option<String>,
90        sub_msg: Option<String>,
91    ) -> Self {
92        ZtkError::Api {
93            code,
94            message: message.into(),
95            sub_code,
96            sub_msg,
97        }
98    }
99
100    /// 创建参数验证错误
101    ///
102    /// # Arguments
103    ///
104    /// * `message` - 验证失败原因
105    pub fn validation(message: impl Into<String>) -> Self {
106        ZtkError::Validation(message.into())
107    }
108
109    /// 创建 URL 编码错误
110    ///
111    /// # Arguments
112    ///
113    /// * `message` - 编码失败原因
114    pub fn url_encode(message: impl Into<String>) -> Self {
115        ZtkError::UrlEncode(message.into())
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_api_error_display() {
125        let err = ZtkError::api(1001, "测试错误");
126        assert_eq!(format!("{}", err), "API 错误 [1001]: 测试错误");
127    }
128
129    #[test]
130    fn test_validation_error_display() {
131        let err = ZtkError::validation("参数不能为空");
132        assert_eq!(format!("{}", err), "参数验证失败: 参数不能为空");
133    }
134
135    #[test]
136    fn test_url_encode_error_display() {
137        let err = ZtkError::url_encode("无效的 URL 字符");
138        assert_eq!(format!("{}", err), "URL 编码失败: 无效的 URL 字符");
139    }
140
141    #[test]
142    fn test_error_is_std_error() {
143        let err: Box<dyn std::error::Error> = Box::new(ZtkError::validation("test"));
144        assert!(err.source().is_none());
145    }
146
147    #[test]
148    fn test_api_error_with_sub() {
149        let err = ZtkError::api_with_sub(
150            1001,
151            "主错误",
152            Some("SUB_001".to_string()),
153            Some("子错误消息".to_string()),
154        );
155        match err {
156            ZtkError::Api {
157                code,
158                message,
159                sub_code,
160                sub_msg,
161            } => {
162                assert_eq!(code, 1001);
163                assert_eq!(message, "主错误");
164                assert_eq!(sub_code, Some("SUB_001".to_string()));
165                assert_eq!(sub_msg, Some("子错误消息".to_string()));
166            }
167            _ => panic!("Expected Api error"),
168        }
169    }
170}