tiktok_api/endpoints/oauth/
common.rs

1use http_api_client_endpoint::{
2    http::{Error as HttpError, StatusCode},
3    Body, Response,
4};
5use serde::de::DeserializeOwned;
6use serde_json::Error as SerdeJsonError;
7use url::ParseError as UrlParseError;
8
9use crate::objects::oauth::ResponseErrorBody;
10
11//
12//
13//
14#[derive(Debug, Clone)]
15pub enum EndpointRet<T>
16where
17    T: core::fmt::Debug + Clone,
18{
19    Ok(T),
20    Other((StatusCode, Result<ResponseErrorBody, Body>)),
21}
22
23//
24//
25//
26#[derive(Debug)]
27pub enum EndpointError {
28    MakeRequestUrlFailed(UrlParseError),
29    MakeRequestFailed(HttpError),
30    DeResponseBodyFailed(SerdeJsonError),
31}
32impl core::fmt::Display for EndpointError {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        write!(f, "{self:?}")
35    }
36}
37impl std::error::Error for EndpointError {}
38
39//
40//
41//
42pub fn endpoint_parse_response<T>(response: Response<Body>) -> Result<EndpointRet<T>, EndpointError>
43where
44    T: core::fmt::Debug + Clone + DeserializeOwned,
45{
46    let status = response.status();
47    #[allow(clippy::single_match)]
48    match status {
49        StatusCode::OK => {
50            use crate::objects::oauth::Message;
51
52            #[allow(clippy::single_match)]
53            match serde_json::from_slice::<Message>(response.body()) {
54                Ok(Message::Success) => {
55                    let ok_json = serde_json::from_slice::<T>(response.body())
56                        .map_err(EndpointError::DeResponseBodyFailed)?;
57
58                    return Ok(EndpointRet::Ok(ok_json));
59                }
60                _ => {}
61            }
62        }
63        _ => {}
64    }
65
66    match serde_json::from_slice::<ResponseErrorBody>(response.body()) {
67        Ok(err_json) => Ok(EndpointRet::Other((status, Ok(err_json)))),
68        Err(_) => Ok(EndpointRet::Other((
69            status,
70            Err(response.body().to_owned()),
71        ))),
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn test_endpoint_parse_response() -> Result<(), Box<dyn std::error::Error>> {
81        let resp_body = include_str!("../../../tests/response_body_files/oauth/refresh_token__err_with_expired_refresh_token.json");
82        let resp = Response::builder()
83            .status(StatusCode::OK)
84            .body(resp_body.as_bytes().to_vec())?;
85
86        match endpoint_parse_response::<()>(resp) {
87            Ok(EndpointRet::Other((status_code, Ok(err_body)))) => {
88                assert_eq!(status_code, StatusCode::OK);
89                assert_eq!(err_body.data.error_code, 10010);
90            }
91            x => panic!("{x:?}"),
92        }
93
94        Ok(())
95    }
96}