1use std::fmt::{Debug, Display, Formatter};
2
3use serde::{Deserialize, Serialize};
4
5use crate::core::{error::LarkAPIError, error_codes::LarkErrorCode, SDKResult};
6
7#[derive(Debug, Serialize, Deserialize)]
9pub struct BaseResponse<T> {
10 #[serde(flatten)]
12 pub raw_response: RawResponse,
13 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 pub fn error_code(&self) -> Option<LarkErrorCode> {
36 LarkErrorCode::from_code(self.code())
37 }
38
39 pub fn is_error_code(&self, code: LarkErrorCode) -> bool {
41 self.code() == code as i32
42 }
43
44 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 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 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 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 pub fn is_retryable(&self) -> bool {
74 self.error_code().map(|c| c.is_retryable()).unwrap_or(false)
75 }
76
77 pub fn suggested_retry_delay(&self) -> Option<u64> {
79 self.error_code().and_then(|c| c.suggested_retry_delay())
80 }
81
82 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 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, ))
107 }
108 }
109
110 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 Ok(self)
136 }
137 }
138 }
139
140 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 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 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 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
260pub trait ApiResponseTrait: for<'a> Deserialize<'a> + Send + Sync + 'static + Debug {
262 fn data_format() -> ResponseFormat;
264
265 fn from_binary(_file_name: String, _body: Vec<u8>) -> Option<Self> {
266 None
267 }
268}
269
270pub enum ResponseFormat {
274 Data,
276 Flatten,
278 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#[derive(Debug, Serialize, Deserialize)]
304pub struct EmptyResponse {}
305
306impl ApiResponseTrait for EmptyResponse {
307 fn data_format() -> ResponseFormat {
308 ResponseFormat::Data
309 }
310}
311
312pub type JsonResponse = serde_json::Value;
314
315impl ApiResponseTrait for JsonResponse {
316 fn data_format() -> ResponseFormat {
317 ResponseFormat::Data
318 }
319}
320
321#[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}