tiktok_api/endpoints/v2/
user_info.rs

1use http_api_client_endpoint::{
2    http::{
3        header::{ACCEPT, AUTHORIZATION, USER_AGENT},
4        Method,
5    },
6    Body, Endpoint, Request, Response,
7};
8use serde::{Deserialize, Serialize};
9use url::Url;
10
11use super::common::{endpoint_parse_response, EndpointError, EndpointRet};
12use crate::objects::v2::{Error, User};
13
14//
15pub const URL: &str = "https://open.tiktokapis.com/v2/user/info/";
16pub const FIELDS_DEFAULT: &str = "open_id,union_id,avatar_url,avatar_url_100,avatar_large_url,display_name,bio_description,profile_deep_link,is_verified,follower_count,following_count,likes_count";
17
18//
19#[derive(Debug, Clone)]
20pub struct UserInfoEndpoint {
21    pub access_token: String,
22    pub fields: String,
23}
24impl UserInfoEndpoint {
25    pub fn new(access_token: impl AsRef<str>) -> Self {
26        Self {
27            access_token: access_token.as_ref().into(),
28            fields: FIELDS_DEFAULT.into(),
29        }
30    }
31
32    pub fn with_fields(mut self, fields: impl AsRef<str>) -> Self {
33        self.fields = fields.as_ref().into();
34        self
35    }
36}
37
38impl Endpoint for UserInfoEndpoint {
39    type RenderRequestError = EndpointError;
40
41    type ParseResponseOutput = EndpointRet<UserInfoResponseBody>;
42    type ParseResponseError = EndpointError;
43
44    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
45        let mut url = Url::parse(URL).map_err(EndpointError::MakeRequestUrlFailed)?;
46        url.query_pairs_mut().append_pair("fields", &self.fields);
47
48        let request = Request::builder()
49            .method(Method::GET)
50            .uri(url.as_str())
51            .header(AUTHORIZATION, format!("Bearer {}", &self.access_token))
52            .header(USER_AGENT, "tiktok-api")
53            .header(ACCEPT, "application/json")
54            .body(vec![])
55            .map_err(EndpointError::MakeRequestFailed)?;
56
57        Ok(request)
58    }
59
60    fn parse_response(
61        &self,
62        response: Response<Body>,
63    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
64        endpoint_parse_response(response)
65    }
66}
67
68//
69#[derive(Serialize, Deserialize, Debug, Clone)]
70pub struct UserInfoResponseBody {
71    pub data: UserInfoResponseBodyData,
72    pub error: Error,
73}
74
75#[derive(Serialize, Deserialize, Debug, Clone)]
76pub struct UserInfoResponseBodyData {
77    pub user: User,
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    use crate::objects::v2::ErrorCode;
85
86    #[test]
87    fn test_render_request() {
88        let req = UserInfoEndpoint::new("TOKEN").render_request().unwrap();
89        assert_eq!(req.method(), Method::GET);
90        assert_eq!(req.uri(), "https://open.tiktokapis.com/v2/user/info/?fields=open_id%2Cunion_id%2Cavatar_url%2Cavatar_url_100%2Cavatar_large_url%2Cdisplay_name%2Cbio_description%2Cprofile_deep_link%2Cis_verified%2Cfollower_count%2Cfollowing_count%2Clikes_count");
91
92        let req = UserInfoEndpoint::new("TOKEN")
93            .with_fields("open_id,union_id,avatar_url")
94            .render_request()
95            .unwrap();
96        assert_eq!(
97            req.uri(),
98            "https://open.tiktokapis.com/v2/user/info/?fields=open_id%2Cunion_id%2Cavatar_url"
99        );
100    }
101
102    #[test]
103    fn test_de_response_body() {
104        match serde_json::from_str::<UserInfoResponseBody>(include_str!(
105            "../../../tests/response_body_files/v2/user_info__full.json"
106        )) {
107            Ok(ok_json) => {
108                assert_eq!(
109                    ok_json.data.user.open_id,
110                    Some("_000fwZ23Mw4RY9cB4lDQyKCgQg4Ft6SyTuE".into())
111                );
112                assert_eq!(ok_json.error.code, ErrorCode::Ok);
113            }
114            x => panic!("{x:?}"),
115        }
116
117        //
118        match serde_json::from_str::<UserInfoResponseBody>(include_str!(
119            "../../../tests/response_body_files/v2/user_info.json"
120        )) {
121            Ok(ok_json) => {
122                assert_eq!(
123                    ok_json.data.user.open_id,
124                    Some("723f24d7-e717-40f8-a2b6-cb8464cd23b4".into())
125                );
126                assert_eq!(ok_json.error.code, ErrorCode::Ok);
127            }
128            x => panic!("{x:?}"),
129        }
130    }
131}