open_lark/core/
api_resp.rs

1use std::fmt::{Debug, Display, Formatter};
2
3use serde::{Deserialize, Serialize};
4
5use crate::core::{error::LarkAPIError, error_codes::LarkErrorCode, SDKResult};
6
7/// 业务返回值
8#[derive(Debug, Serialize, Deserialize)]
9pub struct BaseResponse<T> {
10    /// 响应头
11    #[serde(flatten)]
12    pub raw_response: RawResponse,
13    /// 具体数据
14    pub data: Option<T>,
15}
16
17impl<T> BaseResponse<T> {
18    pub fn success(&self) -> bool {
19        self.raw_response.code == 0
20    }
21
22    pub fn code(&self) -> i32 {
23        self.raw_response.code
24    }
25
26    pub fn msg(&self) -> &str {
27        &self.raw_response.msg
28    }
29
30    pub fn err(&self) -> Option<&ErrorInfo> {
31        self.raw_response.err.as_ref()
32    }
33
34    /// 获取语义化的错误码
35    pub fn error_code(&self) -> Option<LarkErrorCode> {
36        LarkErrorCode::from_code(self.code())
37    }
38
39    /// 检查是否为特定错误码
40    pub fn is_error_code(&self, code: LarkErrorCode) -> bool {
41        self.code() == code as i32
42    }
43
44    /// 检查是否为权限相关错误
45    pub fn is_permission_error(&self) -> bool {
46        self.error_code()
47            .map(|c| c.is_permission_error())
48            .unwrap_or(false)
49    }
50
51    /// 检查是否为认证相关错误
52    pub fn is_auth_error(&self) -> bool {
53        self.error_code()
54            .map(|c| c.is_auth_error())
55            .unwrap_or(false)
56    }
57
58    /// 检查是否为服务器错误
59    pub fn is_server_error(&self) -> bool {
60        self.error_code()
61            .map(|c| c.is_server_error())
62            .unwrap_or(false)
63    }
64
65    /// 检查是否为客户端错误
66    pub fn is_client_error(&self) -> bool {
67        self.error_code()
68            .map(|c| c.is_client_error())
69            .unwrap_or(false)
70    }
71
72    /// 检查是否可以重试
73    pub fn is_retryable(&self) -> bool {
74        self.error_code().map(|c| c.is_retryable()).unwrap_or(false)
75    }
76
77    /// 获取建议的重试延迟时间
78    pub fn suggested_retry_delay(&self) -> Option<u64> {
79        self.error_code().and_then(|c| c.suggested_retry_delay())
80    }
81
82    /// 获取数据或返回友好错误
83    pub fn data_or_error(self) -> Result<T, String> {
84        if self.success() {
85            self.data.ok_or_else(|| "响应成功但数据为空".to_string())
86        } else {
87            let error_msg = if let Some(code) = self.error_code() {
88                code.detailed_description().to_string()
89            } else {
90                format!("{} (错误码: {})", self.msg(), self.code())
91            };
92            Err(error_msg)
93        }
94    }
95
96    /// 获取数据或转换为LarkAPIError
97    pub fn data_or_api_error(self) -> SDKResult<T> {
98        if self.success() {
99            self.data
100                .ok_or_else(|| LarkAPIError::api_error(0, "响应成功但数据为空", None))
101        } else {
102            Err(LarkAPIError::api_error(
103                self.code(),
104                self.msg(),
105                None, // TODO: 可以从响应头中提取request_id
106            ))
107        }
108    }
109
110    /// 处理通用错误,返回处理后的响应或错误
111    pub fn handle_common_errors(self) -> SDKResult<Self> {
112        if self.success() {
113            return Ok(self);
114        }
115
116        match self.error_code() {
117            Some(LarkErrorCode::AccessTokenInvalid) => Err(LarkAPIError::illegal_param(
118                "访问令牌已过期,请重新获取用户授权",
119            )),
120            Some(LarkErrorCode::AppAccessTokenInvalid) => Err(LarkAPIError::illegal_param(
121                "应用访问令牌无效,请检查应用配置",
122            )),
123            Some(LarkErrorCode::TenantAccessTokenInvalid) => Err(LarkAPIError::illegal_param(
124                "租户访问令牌无效,请检查应用权限",
125            )),
126            Some(LarkErrorCode::Forbidden) => Err(LarkAPIError::illegal_param(
127                "权限不足,请检查应用权限配置或用户权限",
128            )),
129            Some(LarkErrorCode::TooManyRequests) => {
130                Err(LarkAPIError::illegal_param("请求过于频繁,请稍后重试"))
131            }
132            Some(LarkErrorCode::NotFound) => Err(LarkAPIError::illegal_param("请求的资源不存在")),
133            _ => {
134                // 对于其他错误,返回原始响应让调用者处理
135                Ok(self)
136            }
137        }
138    }
139
140    /// 获取用户友好的错误描述
141    pub fn user_friendly_error(&self) -> Option<String> {
142        if self.success() {
143            return None;
144        }
145
146        Some(
147            self.error_code()
148                .map(|c| c.detailed_description().to_string())
149                .unwrap_or_else(|| format!("{} (错误码: {})", self.msg(), self.code())),
150        )
151    }
152
153    /// 获取错误的建议解决方案
154    pub fn error_solutions(&self) -> Vec<String> {
155        if self.success() {
156            return vec![];
157        }
158
159        match self.error_code() {
160            Some(LarkErrorCode::AccessTokenInvalid) => vec![
161                "重新获取用户访问令牌".to_string(),
162                "检查令牌是否在有效期内".to_string(),
163            ],
164            Some(LarkErrorCode::AppAccessTokenInvalid) => vec![
165                "检查应用ID和应用密钥".to_string(),
166                "确认应用类型配置正确".to_string(),
167            ],
168            Some(LarkErrorCode::TenantAccessTokenInvalid) => vec![
169                "检查租户权限配置".to_string(),
170                "确认应用已正确安装到企业".to_string(),
171            ],
172            Some(LarkErrorCode::Forbidden) => vec![
173                "检查应用权限范围设置".to_string(),
174                "确认用户具有相应的操作权限".to_string(),
175                "联系管理员添加必要权限".to_string(),
176            ],
177            Some(LarkErrorCode::TooManyRequests) => vec![
178                "降低请求频率".to_string(),
179                "实现请求重试机制".to_string(),
180                "考虑使用请求缓存".to_string(),
181            ],
182            Some(LarkErrorCode::NotFound) => vec![
183                "检查资源ID是否正确".to_string(),
184                "确认资源是否存在".to_string(),
185            ],
186            _ => vec![
187                "检查请求参数是否正确".to_string(),
188                "参考API文档确认调用方式".to_string(),
189            ],
190        }
191    }
192
193    /// 获取相关的帮助链接
194    pub fn help_links(&self) -> Vec<(&'static str, &'static str)> {
195        if self.success() {
196            return vec![];
197        }
198
199        match self.error_code() {
200            Some(code) => vec![
201                (
202                    "官方文档",
203                    code.help_url()
204                        .unwrap_or("https://open.feishu.cn/document/"),
205                ),
206                (
207                    "开发者社区",
208                    "https://getfeishu.cn/hc/zh-cn/categories/360000150856",
209                ),
210            ],
211            None => vec![
212                ("API文档", "https://open.feishu.cn/document/"),
213                (
214                    "开发者社区",
215                    "https://getfeishu.cn/hc/zh-cn/categories/360000150856",
216                ),
217            ],
218        }
219    }
220
221    /// 打印详细的错误信息(用于调试)
222    pub fn print_error_details(&self) {
223        if self.success() {
224            println!("✅ 请求成功");
225            return;
226        }
227
228        println!("❌ 请求失败");
229        println!("错误码: {}", self.code());
230
231        if let Some(error_code) = self.error_code() {
232            println!("错误类型: {}", error_code.description());
233            println!("详细说明: {}", error_code.detailed_description());
234        }
235
236        println!("错误消息: {}", self.msg());
237
238        let solutions = self.error_solutions();
239        if !solutions.is_empty() {
240            println!("\n💡 建议解决方案:");
241            for (i, solution) in solutions.iter().enumerate() {
242                println!("   {}. {}", i + 1, solution);
243            }
244        }
245
246        let help_links = self.help_links();
247        if !help_links.is_empty() {
248            println!("\n🔗 相关链接:");
249            for (name, url) in help_links {
250                println!("   {name}: {url}");
251            }
252        }
253
254        if let Some(delay) = self.suggested_retry_delay() {
255            println!("\n⏱️ 建议重试延迟: {delay}秒");
256        }
257    }
258}
259
260/// 业务返回值格式
261pub trait ApiResponseTrait: for<'a> Deserialize<'a> + Send + Sync + 'static + Debug {
262    /// 是否是标准数据格式, 既是用data包裹数据
263    fn data_format() -> ResponseFormat;
264
265    fn from_binary(_file_name: String, _body: Vec<u8>) -> Option<Self> {
266        None
267    }
268}
269
270/// 响应格式类型
271///
272/// 定义API响应的不同格式类型
273pub enum ResponseFormat {
274    /// 标准数据格式, 既是用data包裹数据
275    Data,
276    /// 扁平数据格式, 既是直接返回数据
277    Flatten,
278    /// 二进制数据格式
279    Binary,
280}
281
282#[derive(Serialize, Deserialize, Debug, Clone, Default)]
283pub struct RawResponse {
284    pub code: i32,
285    pub msg: String,
286    #[serde(rename = "error", default, skip_serializing_if = "Option::is_none")]
287    pub err: Option<ErrorInfo>,
288}
289
290impl ApiResponseTrait for RawResponse {
291    fn data_format() -> ResponseFormat {
292        ResponseFormat::Flatten
293    }
294}
295
296impl Display for RawResponse {
297    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
298        write!(f, "code: {}, msg: {}", self.code, self.msg)
299    }
300}
301
302/// 空响应体
303#[derive(Debug, Serialize, Deserialize)]
304pub struct EmptyResponse {}
305
306impl ApiResponseTrait for EmptyResponse {
307    fn data_format() -> ResponseFormat {
308        ResponseFormat::Data
309    }
310}
311
312/// JSON响应体
313pub type JsonResponse = serde_json::Value;
314
315impl ApiResponseTrait for JsonResponse {
316    fn data_format() -> ResponseFormat {
317        ResponseFormat::Data
318    }
319}
320
321/// 二进制数据响应体
322#[derive(Debug, Serialize, Deserialize)]
323pub struct BinaryResponse {
324    pub file_name: String,
325    pub body: Vec<u8>,
326}
327
328impl ApiResponseTrait for BinaryResponse {
329    fn data_format() -> ResponseFormat {
330        ResponseFormat::Binary
331    }
332
333    fn from_binary(file_name: String, body: Vec<u8>) -> Option<Self> {
334        Some(BinaryResponse { file_name, body })
335    }
336}
337
338#[derive(Serialize, Deserialize, Debug, Clone)]
339pub struct ErrorInfo {
340    #[serde(rename = "key", default, skip_serializing_if = "Option::is_none")]
341    pub log_id: Option<String>,
342    #[serde(rename = "details", default, skip_serializing_if = "Vec::is_empty")]
343    pub details: Vec<CodeErrorDetail>,
344    #[serde(
345        rename = "permission_violations",
346        default,
347        skip_serializing_if = "Vec::is_empty"
348    )]
349    pub permission_violations: Vec<CodeErrorPermissionViolation>,
350    #[serde(
351        rename = "field_violations",
352        default,
353        skip_serializing_if = "Vec::is_empty"
354    )]
355    pub field_violations: Vec<CodeErrorFieldViolation>,
356}
357
358#[derive(Serialize, Deserialize, Debug, Clone)]
359pub struct CodeErrorDetail {
360    #[serde(rename = "key", default, skip_serializing_if = "Option::is_none")]
361    pub key: Option<String>,
362    #[serde(rename = "value", default, skip_serializing_if = "Option::is_none")]
363    pub value: Option<String>,
364}
365
366#[derive(Serialize, Deserialize, Debug, Clone)]
367pub struct CodeErrorPermissionViolation {
368    #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
369    pub type_: Option<String>,
370    #[serde(rename = "subject", default, skip_serializing_if = "Option::is_none")]
371    pub subject: Option<String>,
372    #[serde(
373        rename = "description",
374        default,
375        skip_serializing_if = "Option::is_none"
376    )]
377    pub description: Option<String>,
378}
379
380#[derive(Serialize, Deserialize, Debug, Clone)]
381pub struct CodeErrorFieldViolation {
382    #[serde(rename = "field", default, skip_serializing_if = "Option::is_none")]
383    pub field: Option<String>,
384    #[serde(rename = "value", default, skip_serializing_if = "Option::is_none")]
385    pub value: Option<String>,
386    #[serde(
387        rename = "description",
388        default,
389        skip_serializing_if = "Option::is_none"
390    )]
391    pub description: Option<String>,
392}