1use std::{borrow::Borrow, error::Error, str::FromStr};
19
20use reqwest::{Response, StatusCode, Url, header};
21use serde::de::DeserializeOwned;
22
23pub struct ApiClient {
25 url: String,
26 pub client: reqwest::Client,
27}
28
29impl ApiClient {
30 pub fn new(url: impl Into<String>) -> Self {
40 let mut headers = header::HeaderMap::new();
41 headers.insert(
42 "content-type",
43 header::HeaderValue::from_static("application/json"),
44 );
45 let client = reqwest::ClientBuilder::new()
46 .default_headers(headers)
47 .cookie_store(true)
48 .build()
49 .expect("Failed to build reqwest Client");
50 Self {
51 url: url.into(),
52 client,
53 }
54 }
55
56 fn path(&self, endpoint: &str) -> String {
58 format!("{}/{endpoint}", self.url)
59 }
60
61 async fn get_url<T: DeserializeOwned>(url: Url) -> T {
63 serde_json::from_str(
64 &reqwest::get(url)
65 .await
66 .expect("Failed to send http request")
67 .text()
68 .await
69 .expect("Failed to get response text"),
70 )
71 .expect("Couldn't Parse Value")
72 }
73
74 pub async fn get<T: DeserializeOwned>(&self, endpoint: &str) -> T {
76 let url = reqwest::Url::from_str(&self.path(&endpoint)).unwrap();
77 Self::get_url(url).await
78 }
79
80 pub async fn get_with_body<T, I, K, V>(&self, endpoint: &str, params: I) -> T
82 where
83 T: DeserializeOwned,
84 I: IntoIterator,
85 I::Item: Borrow<(K, V)>,
86 K: AsRef<str>,
87 V: AsRef<str>,
88 {
89 let url = reqwest::Url::parse_with_params(&self.path(&endpoint), params)
90 .expect("Couldn't create get request");
91 Self::get_url(url).await
92 }
93
94 pub async fn post<T: Into<reqwest::Body>>(
96 &self,
97 endpoint: &str,
98 body: T,
99 ) -> Result<Response, Box<dyn Error>> {
100 let url = reqwest::Url::from_str(&self.path(endpoint)).unwrap();
101 Ok(self
102 .client
103 .post(url)
104 .header("content-type", "application/json")
105 .body(body)
106 .send()
107 .await?)
108 }
109
110 pub async fn post_and_deserialize<T: Into<reqwest::Body>, U: DeserializeOwned>(
112 &self,
113 endpoint: &str,
114 body: T,
115 ) -> Result<U, Box<dyn Error>> {
116 let url = reqwest::Url::from_str(&self.path(endpoint)).unwrap();
117
118 let response = self
119 .client
120 .post(url)
121 .header("content-type", "application/json")
122 .body(body)
123 .send()
124 .await?
125 .text()
126 .await?;
127
128 Ok(serde_json::from_str(&response)?)
129 }
130
131 pub async fn post_no_body<T: DeserializeOwned>(
133 &self,
134 endpoint: &str,
135 ) -> Result<T, Box<dyn Error>> {
136 let url = reqwest::Url::from_str(&self.path(endpoint)).unwrap();
137
138 let response = self.client.post(url).send().await?.text().await?;
139
140 println!("Response {response}");
141 Ok(serde_json::from_str(&response)?)
142 }
143
144 pub async fn delete<I, K, V>(
146 &self,
147 client: &reqwest::Client,
148 endpoint: &str,
149 params: I,
150 ) -> StatusCode
151 where
152 I: IntoIterator,
153 I::Item: Borrow<(K, V)>,
154 K: AsRef<str>,
155 V: AsRef<str>,
156 {
157 let url = reqwest::Url::parse_with_params(&self.path(&endpoint), params)
158 .expect("Couldn't create get request");
159 client
160 .delete(url)
161 .header("content-type", "application/json")
162 .send()
163 .await
164 .expect("Failed to send patch request")
165 .status()
166 }
167}