oauth2_twitter/extensions/
internal_users_me_endpoint.rs1use oauth2_client::re_exports::{
4 http::header::{ACCEPT, AUTHORIZATION},
5 serde_json, thiserror, Body, Deserialize, Endpoint, HttpError, Request, Response,
6 SerdeJsonError, Serialize, Url, UrlParseError, MIME_APPLICATION_JSON,
7};
8
9pub const URL: &str = "https://api.twitter.com/2/users/me";
10
11#[derive(Debug, Clone)]
13pub struct UsersMeEndpoint {
14 access_token: String,
15}
16impl UsersMeEndpoint {
17 pub fn new(access_token: impl AsRef<str>) -> Self {
18 Self {
19 access_token: access_token.as_ref().to_owned(),
20 }
21 }
22}
23
24impl Endpoint for UsersMeEndpoint {
25 type RenderRequestError = UsersMeEndpointError;
26
27 type ParseResponseOutput = User;
28 type ParseResponseError = UsersMeEndpointError;
29
30 fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
31 let mut url = Url::parse(URL).map_err(UsersMeEndpointError::UrlParseFailed)?;
32 url.query_pairs_mut()
33 .append_pair("user.fields", "id,name,username,created_at,description");
34
35 let request = Request::builder()
36 .uri(url.as_str())
37 .header(AUTHORIZATION, format!("Bearer {}", &self.access_token))
38 .header(ACCEPT, MIME_APPLICATION_JSON)
39 .body(vec![])
40 .map_err(UsersMeEndpointError::MakeRequestFailed)?;
41
42 Ok(request)
43 }
44
45 fn parse_response(
46 &self,
47 response: Response<Body>,
48 ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
49 if response.status().is_success() {
50 let body = serde_json::from_slice::<ResponseOkBody>(response.body())
51 .map_err(UsersMeEndpointError::DeResponseBodyFailed)?;
52
53 Ok(body.data)
54 } else {
55 let body = serde_json::from_slice::<ResponseFailBody>(response.body())
56 .map_err(UsersMeEndpointError::DeResponseBodyFailed)?;
57
58 Err(UsersMeEndpointError::ResponseBodyIsFail(body))
59 }
60 }
61}
62
63#[derive(Deserialize, Serialize, Debug, Clone)]
64pub struct ResponseOkBody {
65 pub data: User,
66}
67
68#[derive(Deserialize, Serialize, Debug, Clone)]
69pub struct User {
70 pub id: String,
71 pub name: String,
72 pub username: String,
73 pub created_at: Option<String>,
74 pub description: Option<String>,
75}
76
77#[derive(Deserialize, Serialize, Debug, Clone)]
78pub struct ResponseFailBody {
79 pub title: String,
80 pub r#type: String,
81 pub status: usize,
82 pub detail: String,
83}
84
85impl core::fmt::Display for ResponseFailBody {
86 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
87 write!(f, "{self:?}")
88 }
89}
90impl std::error::Error for ResponseFailBody {}
91
92#[derive(thiserror::Error, Debug)]
93pub enum UsersMeEndpointError {
94 #[error("UrlParseFailed {0}")]
95 UrlParseFailed(UrlParseError),
96 #[error("MakeRequestFailed {0}")]
98 MakeRequestFailed(HttpError),
99 #[error("DeResponseBodyFailed {0}")]
101 DeResponseBodyFailed(SerdeJsonError),
102 #[error("ResponseBodyIsFail {0:?}")]
104 ResponseBodyIsFail(ResponseFailBody),
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn de_response_body() {
113 match serde_json::from_str::<ResponseOkBody>(include_str!(
114 "../../tests/response_body_json_files/users_me.json"
115 )) {
116 Ok(body) => {
117 assert_eq!(body.data.name, "HAWE");
118 }
119 Err(err) => panic!("{err}"),
120 }
121
122 match serde_json::from_str::<ResponseFailBody>(include_str!(
123 "../../tests/response_body_json_files/users_me_fail.json"
124 )) {
125 Ok(_) => {}
126 Err(err) => panic!("{err}"),
127 }
128 }
129}