rust_freely/client/
api.rs1pub mod api_wrapper {
3 use std::fmt::Debug;
4
5 use reqwest::{header, Client as ReqwestClient, Error, Method, RequestBuilder, Response, Url};
6 use serde::{de::DeserializeOwned, Serialize};
7
8 use crate::{
9 api_client::{ApiError, Client, RequestError},
10 api_models::responses::ResponseModel,
11 };
12
13 #[derive(Clone, Debug)]
14 pub struct Api {
16 client: Client,
17 }
18
19 impl Api {
20 pub fn new(client: Client) -> Self {
22 Api { client }
23 }
24
25 pub fn base(&self) -> String {
27 self.client.url()
28 }
29
30 pub fn token(&self) -> Option<String> {
32 self.client.token()
33 }
34
35 pub fn is_authenticated(&self) -> bool {
37 self.client.is_authenticated()
38 }
39
40 pub fn url(&self, endpoint: &str) -> Result<Url, ApiError> {
42 if let Ok(result) = Url::parse(self.base().as_str()) {
43 if let Ok(result) = result.join(vec!["/api", endpoint].join("").as_str()) {
44 Ok(result)
45 } else {
46 Err(ApiError::UrlError {})
47 }
48 } else {
49 Err(ApiError::UrlError {})
50 }
51 }
52
53 fn http(&self) -> Result<ReqwestClient, Error> {
54 let mut headers = header::HeaderMap::new();
55 headers.insert(
56 "Accept",
57 header::HeaderValue::from_static("application/json"),
58 );
59 headers.insert(
60 "Content-Type",
61 header::HeaderValue::from_static("application/json"),
62 );
63
64 ReqwestClient::builder().default_headers(headers).build()
65 }
66
67 pub fn request(&self, endpoint: &str, method: Method) -> Result<RequestBuilder, ApiError> {
69 if let Ok(http) = self.http() {
70 if let Ok(url) = self.url(endpoint) {
71 let mut request = http.request(method, url.clone());
72 println!("{:?}", url);
73 if let Some(token) = self.token() {
74 request = request.header(header::AUTHORIZATION, format!("Token {token}"));
75 }
76 Ok(request)
77 } else {
78 Err(ApiError::UrlError {})
79 }
80 } else {
81 Err(ApiError::UnknownError {})
82 }
83 }
84
85 pub async fn extract_response<T: DeserializeOwned + Debug>(
87 &self,
88 response: Response,
89 ) -> Result<T, ApiError> {
90 match response.error_for_status() {
91 Ok(resp) => {
92 let text = resp.text().await.unwrap();
93 serde_json::from_str::<ResponseModel>(text.clone().as_str())
94 .or(Err(ApiError::ParseError {
95 text: text.clone(),
96 }))
97 .and_then(|v| {
98 serde_json::from_value::<T>(v.data).or(Err(ApiError::ParseError {
99 text: text.clone(),
100 }))
101 })
102 }
103 Err(resp) => Err(ApiError::Request {
104 error: RequestError {
105 code: resp.status().map_or(0, |s| s.as_u16()),
106 reason: Some(resp.to_string()),
107 },
108 }),
109 }
110 }
111
112 pub async fn get<T: DeserializeOwned + Debug>(
114 &self,
115 endpoint: &str,
116 ) -> Result<T, ApiError> {
117 if let Ok(response) = self.request(endpoint, Method::GET)?.send().await {
118 self.extract_response::<T>(response).await
119 } else {
120 Err(ApiError::ConnectionError {})
121 }
122 }
123
124 pub async fn delete(
126 &self,
127 endpoint: &str,
128 ) -> Result<(), ApiError> {
129 if let Ok(response) = self.request(endpoint, Method::DELETE)?.send().await {
130 match response.error_for_status() {
131 Ok(_) => Ok(()),
132 Err(resp) => Err(ApiError::Request {
133 error: RequestError {
134 code: resp.status().map_or(0, |s| s.as_u16()),
135 reason: Some(resp.to_string()),
136 },
137 })
138 }
139
140 } else {
141 Err(ApiError::ConnectionError {})
142 }
143 }
144
145 pub async fn post<T: DeserializeOwned + Debug, D: Serialize>(
147 &self,
148 endpoint: &str,
149 data: Option<D>,
150 ) -> Result<T, ApiError> {
151 if let Ok(response) = self
152 .request(endpoint, Method::POST)?
153 .json(&data)
154 .send()
155 .await
156 {
157 self.extract_response::<T>(response).await
158 } else {
159 Err(ApiError::ConnectionError {})
160 }
161 }
162 }
163}