wx_sdk/
error.rs

1//! This module define the types for error handling.
2//!
3//! Most the function call on `wx-sdk` return a [SdkResult], it's a type of `std::result::Result<T, SdkError>` wrapper.
4
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7// use tonic::codegen::http::request;
8
9/// Almost every WeChat's api calling will return a JSON value contains `errcode` and `errmsg`, that is a struct for it.
10/// When the `errcode == 0`,  it can transmute to `SdkResult<()>`.
11#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Error)]
12#[error("Wechat API response error: errcode {errcode}, errmsg {errmsg}")]
13pub struct CommonError {
14    pub errcode: i32,
15    pub errmsg: String,
16}
17
18/// Enum for the return result of http calling WeChat's api.
19#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
20#[serde(untagged)]
21pub enum CommonResponse<T> {
22    Ok(T),
23    Err(CommonError),
24}
25
26/// The SDK self-defined error enum.
27#[derive(Error, Debug)]
28pub enum SdkError {
29    #[error("reqwest Error")]
30    ReqwestError(#[from] reqwest::Error),
31
32    #[error("wx received event parse error")]
33    XmlParseError(#[from] roxmltree::Error),
34
35    #[error("get access token error")]
36    AccessTokenError(CommonError),
37
38    #[error(transparent)]
39    WxApiError(#[from] CommonError),
40
41    #[error(transparent)]
42    UrlParseError(#[from] url::ParseError),
43
44    #[error("api request params error: {0}")]
45    InvalidParams(String),
46
47    #[error("parse received encrypt msg error: wrong signature")]
48    InvalidSignature,
49
50    #[error("parse received encrypt msg error: invalid appid")]
51    InvalidAppid,
52
53    #[error("decrypt msg error: {0}")]
54    MsgDecryptError(String),
55
56    #[error("encrypt msg error: {0}")]
57    MsgEncryptError(String),
58
59    #[error("Exile write xml error")]
60    XmlWriteError(#[from] exile::error::Error),
61}
62
63/// A wrap of `std::result::Result<T, SdkError>`.
64pub type SdkResult<T> = std::result::Result<T, SdkError>;
65
66/// When the `errcode == 0`,  it can transmute to `SdkResult<()>`.
67impl From<CommonError> for SdkResult<()> {
68    fn from(e: CommonError) -> Self {
69        if e.errcode == 0 {
70            Ok(())
71        } else {
72            Err(SdkError::WxApiError(e))
73        }
74    }
75}
76
77/// Trans CommonResponse<T> to SdkResult<T> when the error case is `SdkError::WxApiError(_)`.
78impl<T> From<CommonResponse<T>> for SdkResult<T> {
79    fn from(r: CommonResponse<T>) -> Self {
80        match r {
81            CommonResponse::Ok(t) => Ok(t),
82            CommonResponse::Err(e) => Err(SdkError::WxApiError(e)),
83        }
84    }
85}
86
87/// Unwrap the `CommonResponse<CommonError>` to SdkResult<()> or `SdkError::WxApiError(_)`.
88impl From<CommonResponse<CommonError>> for SdkResult<()> {
89    fn from(r: CommonResponse<CommonError>) -> Self {
90        match r {
91            CommonResponse::Ok(e) => {
92                if e.errcode == 0 {
93                    Ok(())
94                } else {
95                    Err(SdkError::WxApiError(e))
96                }
97            }
98            CommonResponse::Err(e) => {
99                if e.errcode == 0 {
100                    Ok(())
101                } else {
102                    Err(SdkError::WxApiError(e))
103                }
104            }
105        }
106    }
107}
108
109#[test]
110fn test_error_from() {
111    let input = r#"{"errcode": 0,"errmsg":"success"}"#;
112    let expected = CommonResponse::Ok(CommonError {
113        errcode: 0,
114        errmsg: "success".to_string(),
115    });
116    assert_eq!(expected.clone(), serde_json::from_str(input).unwrap());
117
118    let into: SdkResult<()> = expected.clone().into();
119    assert!(into.is_ok());
120
121    let input = r#"{"errcode":40013,"errmsg":"invalid appid"}"#;
122    let expected = CommonResponse::Ok(CommonError {
123        errcode: 40013,
124        errmsg: "invalid appid".to_string(),
125    });
126    assert_eq!(expected.clone(), serde_json::from_str(input).unwrap());
127
128    let into: SdkResult<()> = expected.clone().into();
129    assert!(into.is_err());
130}
131
132#[test]
133fn test_data_and_error() {
134    #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
135    pub struct Data {
136        pub aid: String,
137        pub session_key: String,
138    }
139    let input = r#"{ "aid": "ssss", "session_key": "dddddd", "errcode": 22,"errmsg":"errrrr"}"#;
140    // let expected = &CommonResponse::<Data>::Err(CommonError {
141    //     errcode: 22,
142    //     errmsg: "errrrr".to_string(),
143    // });
144
145    let expected_data = &CommonResponse::<Data>::Ok(Data {
146        aid: "ssss".to_string(),
147        session_key: "dddddd".to_string(),
148    });
149
150    assert_eq!(expected_data, &serde_json::from_str(input).unwrap());
151}