nodesty_api_library/
client.rs

1use 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}