Skip to main content

nubis_sdk/
client.rs

1use crate::error::{NubisError, Result};
2use crate::types::NubisConfig;
3use reqwest::{Client, Response};
4use std::time::Duration;
5
6/// Main Nubis SDK client
7pub struct NubisClient {
8    client: Client,
9    base_url: String,
10}
11
12impl NubisClient {
13    /// Create a new Nubis client with the given API key
14    pub fn new(api_key: String) -> Self {
15        Self::with_config(NubisConfig {
16            api_key,
17            ..Default::default()
18        })
19    }
20
21    /// Create a new Nubis client with custom configuration
22    pub fn with_config(config: NubisConfig) -> Self {
23        let client_builder = Client::builder()
24            .timeout(config.timeout.unwrap_or(Duration::from_secs(30)))
25            .default_headers({
26                let mut headers = reqwest::header::HeaderMap::new();
27                headers.insert(
28                    reqwest::header::CONTENT_TYPE,
29                    "application/json".parse().unwrap(),
30                );
31                headers.insert(
32                    reqwest::header::AUTHORIZATION,
33                    format!("Bearer {}", config.api_key).parse().unwrap(),
34                );
35                headers
36            });
37
38        let client = client_builder.build().expect("Failed to create HTTP client");
39
40        Self {
41            client,
42            base_url: config.base_url,
43        }
44    }
45
46    /// Make a GET request
47    pub(crate) async fn get<T>(&self, path: &str) -> Result<T>
48    where
49        T: serde::de::DeserializeOwned,
50    {
51        let url = format!("{}{}", self.base_url, path);
52        let response = self.client.get(&url).send().await?;
53        self.handle_response(response).await
54    }
55
56    /// Make a GET request with query parameters
57    pub(crate) async fn get_with_params<T>(&self, path: &str, params: &[(&str, &str)]) -> Result<T>
58    where
59        T: serde::de::DeserializeOwned,
60    {
61        let url = format!("{}{}", self.base_url, path);
62        let mut request = self.client.get(&url);
63        for (key, value) in params {
64            request = request.query(&[(key, value)]);
65        }
66        let response = request.send().await?;
67        self.handle_response(response).await
68    }
69
70    /// Make a POST request
71    pub(crate) async fn post<T, B>(&self, path: &str, body: &B) -> Result<T>
72    where
73        T: serde::de::DeserializeOwned,
74        B: serde::Serialize,
75    {
76        let url = format!("{}{}", self.base_url, path);
77        let response = self.client.post(&url).json(body).send().await?;
78        self.handle_response(response).await
79    }
80
81    /// Make a PUT request
82    pub(crate) async fn put<T, B>(&self, path: &str, body: &B) -> Result<T>
83    where
84        T: serde::de::DeserializeOwned,
85        B: serde::Serialize,
86    {
87        let url = format!("{}{}", self.base_url, path);
88        let response = self.client.put(&url).json(body).send().await?;
89        self.handle_response(response).await
90    }
91
92    /// Make a DELETE request
93    pub(crate) async fn delete<T>(&self, path: &str) -> Result<T>
94    where
95        T: serde::de::DeserializeOwned,
96    {
97        let url = format!("{}{}", self.base_url, path);
98        let response = self.client.delete(&url).send().await?;
99        self.handle_response(response).await
100    }
101
102    /// Handle HTTP response and extract JSON or error
103    async fn handle_response<T>(&self, response: Response) -> Result<T>
104    where
105        T: serde::de::DeserializeOwned,
106    {
107        let status = response.status();
108
109        if status.is_success() {
110            let text = response.text().await?;
111            if text.is_empty() {
112                // Empty response for DELETE operations
113                serde_json::from_str("{}").map_err(NubisError::Serialization)
114            } else {
115                serde_json::from_str(&text).map_err(NubisError::Serialization)
116            }
117        } else {
118            let error_text = response.text().await.unwrap_or_default();
119            let error_message = if let Ok(api_error) = serde_json::from_str::<crate::types::ApiErrorResponse>(&error_text) {
120                api_error.error.message
121            } else {
122                format!("HTTP {}: {}", status, error_text)
123            };
124
125            Err(NubisError::Api {
126                status: status.as_u16(),
127                message: error_message,
128            })
129        }
130    }
131}