Rustiny/api/
ApiClient.rs

1use std::borrow::Borrow;
2use std::collections::HashMap;
3use reqwest::{Client, Response};
4use anyhow::Result;
5use serde_json::Value;
6use std::sync::atomic::AtomicBool;
7use serde::de::DeserializeOwned;
8use tokio::sync::Mutex;
9
10pub struct ApiClient {
11    pub(crate) apikey: String,
12    DEBUG_MODE: Mutex<AtomicBool>,
13}
14
15impl ApiClient {
16    pub fn new(apikey: &str) -> Self {
17        Self {
18            apikey: String::from(apikey),
19            DEBUG_MODE: Mutex::new(AtomicBool::new(false)),
20        }
21    }
22
23    /// Enables Debug Mode
24    ///
25    /// Prints all requests and their responses as they come through
26    /// usually only needed for development of the API but may be useful
27    /// to someone wanting to learn the inner-workings of the system.
28    pub async fn enable_debug_mode(self) -> Self {
29        let mut temp = self.DEBUG_MODE.lock().await;
30        *temp = AtomicBool::new(true);
31        drop(temp);
32        self
33    }
34
35    pub async fn is_debug_enabled(&self) -> bool {
36        *self.DEBUG_MODE.lock().await.get_mut()
37    }
38
39    /// Clones the ApiClient
40    pub async fn clone(&self) -> Self {
41        Self {
42            apikey: self.apikey.clone(),
43            DEBUG_MODE: Mutex::new(AtomicBool::new(self.is_debug_enabled().await)),
44        }
45    }
46
47    pub async fn get(&self, url: String) -> Result<String> {
48        self.get_params(url, HashMap::new()).await
49    }
50
51    pub async fn get_params(&self, url: String, map: HashMap<&str, &str>) -> Result<String> {
52        let client = reqwest::Client::new();
53        let resp = client
54            .get(url.clone())
55            .header("X-API-KEY", self.apikey.as_str())
56            .query(&map)
57            .send()
58            .await?;
59
60        let text = resp.text().await?;
61
62        if self.is_debug_enabled().await {
63            println!("GET {}", url);
64            println!("{}", text.clone());
65        }
66
67
68        Ok(text)
69    }
70
71    pub async fn get_parse<T: DeserializeOwned>(&self, url: String, dewrap: bool) -> Result<T> {
72        if dewrap {
73            let val = serde_json::from_str::<Value>(self.get(url.clone()).await?.as_str())?;
74
75            return Ok(serde_json::from_value::<T>(val["Response"].clone())?)
76        }
77
78        let text = self.get(url.clone()).await?;
79
80        let r = serde_json::from_str::<T>(text.as_str())?;
81
82        Ok(r)
83    }
84
85    pub async fn get_parse_params<T: DeserializeOwned>(&self, url: String, dewrap: bool, map: HashMap<&str, &str>) -> Result<T> {
86        if dewrap {
87            let val = serde_json::from_str::<Value>(self.get_params(url.clone(), map).await?.as_str())?;
88
89            return Ok(serde_json::from_value::<T>(val["Response"].clone())?)
90        }
91
92        let text = self.get_params(url, map).await?;
93
94        Ok(serde_json::from_str::<T>(text.as_str())?)
95    }
96
97    pub async fn post(&self, url: String, body: String) -> Result<String> {
98        self.post_params(url, body, HashMap::new()).await
99    }
100
101    pub async fn post_params(&self, url: String, body: String, map: HashMap<&str, &str>) -> Result<String> {
102        let client = Client::new();
103        let resp = client
104            .post(url.clone())
105            .body(body.clone())
106            .header("X-API-KEY", self.apikey.as_str())
107            .query(&map)
108            .send()
109            .await?;
110
111        let text = resp.text().await?;
112
113        if self.is_debug_enabled().await {
114            println!("POST {}", url);
115            println!("Body - {}", body);
116            println!("{}", text.clone());
117        }
118
119        Ok(text)
120    }
121
122    pub async fn post_parse<T: DeserializeOwned>(&self, url: String, body: String, dewrap: bool) -> Result<T> {
123        if dewrap {
124            let val = serde_json::from_str::<Value>(self.post(url, body).await?.as_str())?;
125
126            return Ok(serde_json::from_value::<T>(val["Response"].clone())?)
127        }
128
129        let text = self.post(url, body).await?;
130
131        let r = serde_json::from_str::<T>(text.as_str())?;
132
133        Ok(r)
134    }
135
136    pub async fn post_parse_params<T: DeserializeOwned>(&self, url: String, body: String, map: HashMap<&str, &str>, dewrap: bool) -> Result<T> {
137        if dewrap {
138            let val = serde_json::from_str::<Value>(self.post_params(url, body, map).await?.as_str())?;
139
140            return Ok(serde_json::from_value::<T>(val["Response"].clone())?)
141        }
142
143        let text = self.post_params(url, body, map).await?;
144
145        Ok(serde_json::from_str::<T>(text.as_str())?)
146    }
147}
148
149pub trait HandleValue {
150    fn handle(value: Value) -> Value;
151}
152
153fn encode_url(url: String) -> String {
154    url.replace(" ", "%20")
155}