api_resp/
lib.rs

1//! 该模块定义通用的异步/远程接口调用结果。
2use std::error::Error;
3use std::fmt::{Debug, Display};
4use log::error;
5use serde::{Serialize,Deserialize};
6
7/// API接口响应数据结构。
8#[derive(Debug, Serialize, Deserialize)]
9pub struct ApiResp {
10    /// 执行是否成功
11    success: bool,
12    /// 响应代码
13    code: i32,
14    /// 响应附带消息,通常是错误提示信息。
15    message: String,
16    /// 响应数据。
17    data: Option<serde_json::Value>,
18}
19
20impl ApiResp {
21    pub fn is_success(&self) -> bool { self.success }
22
23    pub fn get_code(&self) -> i32 { self.code }
24
25    pub fn get_message(&self) -> &String { &self.message }
26
27    pub fn get_data(&self) -> &Option<serde_json::Value> { &self.data }
28
29    pub fn to_json(&self) -> String {
30        match serde_json::to_string(&self) {
31            Ok(json) => json,
32            Err(e) => {
33                error!("序列化json字符串时出错!{}", e);
34                let err_resp = ApiResp::error(-1, "处理响应结果时出错!".to_string());
35                serde_json::to_string(&err_resp).unwrap()
36            }
37        }
38    }
39}
40
41impl ApiResp {
42    /// 构造一个成功的响应对象。
43    ///
44    /// # Arguments
45    ///
46    /// * `data`: 业务数据。
47    ///
48    /// returns: ApiResp
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use api_resp::ApiResp;
54    /// use serde_json::json;
55    /// let data = vec![1,1,3,5];
56    /// let resp = ApiResp::success(json!(data));
57    /// ```
58    pub fn success(data: serde_json::Value) -> ApiResp {
59        ApiResp {
60            success: true,
61            code: 0,
62            message: "".to_string(),
63            data: Some(data),
64        }
65    }
66
67    /// 构造一个成功的简单响应对象,不带任何消息。
68    ///
69    /// returns: ApiResp 返回成功响应。
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use api_resp::ApiResp;
75    /// let resp = ApiResp::suc();
76    /// ```
77    pub fn suc() -> ApiResp {
78        ApiResp {
79            success: true,
80            code: 0,
81            message: "".to_string(),
82            data: None,
83        }
84    }
85
86
87    /// 构造一个失败的响应对象。
88    ///
89    /// # Arguments
90    ///
91    /// * `code`: 失败代码。根据具体的业务接口约定取值列表。
92    /// * `message`: 失败信息。
93    ///
94    /// returns: ApiResp
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use api_resp::ApiResp;
100    /// let resp = ApiResp::fail(-1, String::from("查询信息失败,原因:..."));
101    /// ```
102    pub fn error(code: i32, message: String) -> ApiResp {
103        ApiResp {
104            success: false,
105            code,
106            message,
107            data: None,
108        }
109    }
110}
111
112/// 简写的接口返回数据结构定义。
113pub type DaoResult = Result<ApiResp, Box<dyn Error>>;
114
115/// 将API调用结果转换为对外数据形式的特性声明。
116pub trait TransformResult {
117    /// 将API结果转换为JSON字符串。
118    ///
119    /// # Arguments
120    ///
121    /// * `err_log`: 客制化的出错日志信息。
122    ///
123    /// returns: String 返回JSON字符串。
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use serde::{Deserialize, Serialize};
129    /// use std::fmt::{Debug, Display};
130    /// use api_resp::TransformResult;
131    /// #[derive(Debug, Serialize, Deserialize)]
132    /// struct Dept {
133    ///     id: Option<String>,
134    ///     pid: Option<String>,
135    ///     other_attr: Option<i32>
136    /// }
137    ///
138    /// impl TransformResult for Dept {
139    ///     fn to_json_str<T>(self, err_log: T) -> String where T: Debug + Display {
140    ///         serde_json::to_string(&self).unwrap()
141    ///     }
142    /// }
143    ///
144    /// let d = Dept {id: Some("01".to_string()), pid: None, other_attr: Some(10)};
145    ///
146    /// let json_str = d.to_json_str("执行出错".to_string());
147    /// println!("json_str: {}", json_str);
148    /// ```
149    fn to_json_str<T>(self, err_log: T) -> String where T: Debug + Display;
150}
151
152impl TransformResult for DaoResult {
153    fn to_json_str<T>(self, err_log: T) -> String where T: Debug + Display {
154        let ret: ApiResp = match self {
155            Ok(r) => r,
156            Err(e) => {
157                error!("{} {:?}", err_log, e);
158                ApiResp::error(-1, e.to_string())
159            }
160        };
161        serde_json::to_string(&ret).unwrap()
162    }
163}
164
165/// 回滚当前的事务后退出当前函数,返回包含通用错误信息的结果对象。
166#[macro_export]
167macro_rules! rollback {
168    ($resp: expr, $tx: expr, $code: expr) => {
169        if let Err(e) = $resp {
170            $tx.rollback().await?;
171            return Ok(ApiResp::error($code, e.to_string()));
172        }
173    };
174}
175
176/// 当出现错误或更新记录数未0时,回滚当前的事务后退出当前函数,返回包含通用错误信息的结果对象。
177#[macro_export]
178macro_rules! rollback_for_no_match {
179    ($resp: expr, $tx: expr, $code: expr) => {
180        match $resp {
181            Err(e) => {
182                $tx.rollback().await?;
183                return Ok(ApiResp::error($code, e.to_string()));
184            },
185            Ok(r) if r.rows_affected == 0 => {
186                $tx.rollback().await?;
187                return Ok(ApiResp::error($code, "未匹配到目标记录".to_string()));
188            },
189            _ => {}
190        }
191    };
192}
193
194#[cfg(test)]
195mod tests {
196    use serde_json::json;
197    use super::*;
198
199    #[derive(Debug, Serialize, Deserialize)]
200    struct PingPang {
201        color: String,
202        weight: f64,
203    }
204
205    #[test]
206    fn test_resp() {
207        // 成功结果,没有业务数据。
208        let suc_json = ApiResp::suc().to_json();
209        println!("suc_json: {}", suc_json);
210        let orig_suc: ApiResp = serde_json::from_str(suc_json.as_str()).unwrap();
211        assert!(orig_suc.is_success());
212
213        // 成功结果,带有业务数据。
214        let vals = vec![
215            PingPang {color: "white".to_string(), weight: 10.0},
216            PingPang {color: "yellow".to_string(), weight: 11.5},
217        ];
218        let suc_data = ApiResp::success(json!(vals)).to_json();
219        println!("suc_data: {}", suc_data);
220        let orig_suc_data: ApiResp = serde_json::from_str(suc_data.as_str()).unwrap();
221        assert!(orig_suc_data.is_success());
222
223        // 失败结果。
224        let fail_json = ApiResp::error(-1, String::from("交易出错了")).to_json();
225        println!("fail_json: {}", fail_json);
226        let orig_fail: ApiResp = serde_json::from_str(fail_json.as_str()).unwrap();
227        assert!(!orig_fail.is_success());
228    }
229}