nodesty_api_library/
client.rs1use crate::models::RestClientOptions;
2use crate::ApiResponse;
3use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
4use reqwest::{Client, ClientBuilder, Error, Method};
5use serde::de::DeserializeOwned;
6use serde_json;
7use serde_json::Value;
8use std::sync::Arc;
9use std::time::Duration;
10
11pub struct NodestyApiClient {
12 client: Client,
13 base_url: String,
14}
15
16impl NodestyApiClient {
17 pub fn new(options: RestClientOptions) -> Result<Arc<Self>, Error> {
18 let auth_header = HeaderValue::from_str(&format!("PAT {}", options.access_token))
19 .expect("Invalid authorization token");
20
21 let timeout = Duration::from_millis(options.timeout_ms.unwrap_or(30_000));
22
23 let mut headers = HeaderMap::new();
24 headers.insert(AUTHORIZATION, auth_header);
25
26 let client = ClientBuilder::new()
27 .default_headers(headers)
28 .timeout(timeout)
29 .connect_timeout(timeout)
30 .build()?;
31
32 Ok(Arc::new(Self {
33 client,
34 base_url: options.base_url.clone(),
35 }))
36 }
37
38 pub async fn send_request<T: DeserializeOwned>(
39 &self,
40 method: Method,
41 path: &str,
42 body: Option<Value>,
43 ) -> Result<ApiResponse<T>, Error> {
44 let url = format!("{}{}", self.base_url, path);
45 let mut request = self.client.request(method, &url);
46
47 if let Some(body) = body {
48 request = request.json(&body);
49 }
50
51 let response = request.send().await?;
52 let status = response.status();
53 let raw_data: Value = response.json().await?;
54
55 let api_response = if !status.is_success() {
56 ApiResponse {
57 success: false,
58 error: raw_data["message"].as_str().map(|s| s.to_string()),
59 data: None,
60 }
61 } else {
62 ApiResponse {
63 success: true,
64 error: None,
65 data: serde_json::from_value(raw_data).ok(),
66 }
67 };
68
69 Ok(api_response)
70 }
71}