twapi_reqwest/
v2.rs

1use reqwest::{multipart::Form, Error, Response};
2use serde_json::Value;
3use std::time::Duration;
4use twapi_oauth::oauth2_authorization_header;
5
6pub struct Client {
7    bearer_token: String,
8    timeout_sec: Option<Duration>,
9}
10
11impl Client {
12    pub fn new(bearer_token: &str, timeout_sec: Option<Duration>) -> Self {
13        Self {
14            bearer_token: bearer_token.to_owned(),
15            timeout_sec,
16        }
17    }
18
19    pub async fn new_from_key(
20        consumer_key: &str,
21        consumer_secret: &str,
22        timeout_sec: Option<Duration>,
23    ) -> Result<Option<Self>, Error> {
24        Ok(
25            crate::oauth::get_bearer_token(&consumer_key, &consumer_secret, timeout_sec)
26                .await?
27                .map(|bearer_token| Self::new(&bearer_token, None)),
28        )
29    }
30
31    pub async fn new_by_env(timeout_sec: Option<Duration>) -> Result<Option<Self>, Error> {
32        let consumer_key = match std::env::var("CONSUMER_KEY") {
33            Ok(consumer_key) => consumer_key,
34            Err(_) => return Ok(None),
35        };
36        let consumer_secret = match std::env::var("CONSUMER_SECRET") {
37            Ok(consumer_key) => consumer_key,
38            Err(_) => return Ok(None),
39        };
40        Self::new_from_key(&consumer_key, &consumer_secret, timeout_sec).await
41    }
42
43    fn make_header(&self) -> String {
44        oauth2_authorization_header(&self.bearer_token)
45    }
46
47    pub async fn get(
48        &self,
49        url: &str,
50        query_options: &Vec<(&str, &str)>,
51    ) -> Result<Response, Error> {
52        crate::raw::get(url, query_options, &self.make_header(), self.timeout_sec).await
53    }
54
55    pub async fn post(
56        &self,
57        url: &str,
58        query_options: &Vec<(&str, &str)>,
59        form_options: &Vec<(&str, &str)>,
60    ) -> Result<Response, Error> {
61        crate::raw::post(
62            url,
63            query_options,
64            form_options,
65            &self.make_header(),
66            self.timeout_sec,
67        )
68        .await
69    }
70
71    pub async fn json(
72        &self,
73        url: &str,
74        query_options: &Vec<(&str, &str)>,
75        data: &Value,
76    ) -> Result<Response, Error> {
77        crate::raw::json(
78            url,
79            query_options,
80            data,
81            &self.make_header(),
82            self.timeout_sec,
83        )
84        .await
85    }
86
87    pub async fn put(
88        &self,
89        url: &str,
90        query_options: &Vec<(&str, &str)>,
91    ) -> Result<Response, Error> {
92        crate::raw::put(url, query_options, &self.make_header(), self.timeout_sec).await
93    }
94
95    pub async fn delete(
96        &self,
97        url: &str,
98        query_options: &Vec<(&str, &str)>,
99    ) -> Result<Response, Error> {
100        crate::raw::delete(url, query_options, &self.make_header(), self.timeout_sec).await
101    }
102
103    pub async fn multipart(
104        &self,
105        url: &str,
106        query_options: &Vec<(&str, &str)>,
107        data: Form,
108    ) -> Result<Response, Error> {
109        crate::raw::multipart(
110            url,
111            query_options,
112            data,
113            &self.make_header(),
114            self.timeout_sec,
115        )
116        .await
117    }
118}
119
120pub async fn get(
121    url: &str,
122    query_options: &Vec<(&str, &str)>,
123    bearer_token: &str,
124    timeout_sec: Option<Duration>,
125) -> Result<Response, Error> {
126    let client = Client::new(bearer_token, timeout_sec);
127    client.get(url, query_options).await
128}
129
130pub async fn post(
131    url: &str,
132    query_options: &Vec<(&str, &str)>,
133    form_options: &Vec<(&str, &str)>,
134    bearer_token: &str,
135    timeout_sec: Option<Duration>,
136) -> Result<Response, Error> {
137    let client = Client::new(bearer_token, timeout_sec);
138    client.post(url, query_options, form_options).await
139}
140
141pub async fn json(
142    url: &str,
143    query_options: &Vec<(&str, &str)>,
144    data: &Value,
145    bearer_token: &str,
146    timeout_sec: Option<Duration>,
147) -> Result<Response, Error> {
148    let client = Client::new(bearer_token, timeout_sec);
149    client.json(url, query_options, data).await
150}
151
152pub async fn put(
153    url: &str,
154    query_options: &Vec<(&str, &str)>,
155    bearer_token: &str,
156    timeout_sec: Option<Duration>,
157) -> Result<Response, Error> {
158    let client = Client::new(bearer_token, timeout_sec);
159    client.put(url, query_options).await
160}
161
162pub async fn delete(
163    url: &str,
164    query_options: &Vec<(&str, &str)>,
165    bearer_token: &str,
166    timeout_sec: Option<Duration>,
167) -> Result<Response, Error> {
168    let client = Client::new(bearer_token, timeout_sec);
169    client.delete(url, query_options).await
170}
171
172pub async fn multipart(
173    url: &str,
174    query_options: &Vec<(&str, &str)>,
175    data: Form,
176    bearer_token: &str,
177    timeout_sec: Option<Duration>,
178) -> Result<Response, Error> {
179    let client = Client::new(bearer_token, timeout_sec);
180    client.multipart(url, query_options, data).await
181}
182
183#[cfg(test)]
184mod tests {
185    use crate::*;
186    use serde_json::Value;
187    use std::env;
188
189    #[tokio::test]
190    async fn test_api() {
191        let consumer_key = env::var("CONSUMER_KEY").unwrap();
192        let consumer_secret = env::var("CONSUMER_SECRET").unwrap();
193        let bearer_token = oauth::get_bearer_token(&consumer_key, &consumer_secret, None)
194            .await
195            .unwrap()
196            .unwrap();
197
198        // search
199        let res: Value = v2::get(
200            "https://api.twitter.com/1.1/search/tweets.json",
201            &vec![("q", "*abc"), ("count", "2")],
202            &bearer_token,
203            None,
204        )
205        .await
206        .unwrap()
207        .json()
208        .await
209        .unwrap();
210        println!("{:?}", res);
211    }
212}