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        println!("Ham API Yanıtı ({} {}): {:?}", status, path, raw_data);
56
57        let final_api_response: ApiResponse<T> = if status.is_success() {
58            match serde_json::from_value::<T>(raw_data.clone()) {
59                Ok(data) => {
60                    ApiResponse {
61                        success: true,
62                        error: None,
63                        data: Some(data),
64                    }
65                },
66                Err(direct_deserialize_err) => {
67                    match serde_json::from_value::<ApiResponse<T>>(raw_data.clone()) {
68                        Ok(api_resp) => {
69                            api_resp
70                        },
71                        Err(api_resp_deserialize_err) => {
72                            ApiResponse {
73                                success: false,
74                                error: Some(format!(
75                                    "JSON ayrıştırma hatası (HTTP {}): Beklenen 'ApiResponse' veya direkt veri formatında değil. \
76                                     Yanıt: {:?} - Doğrudan T ayrıştırma hatası: {} - ApiResponse<T> ayrıştırma hatası: {}",
77                                    status.as_u16(), raw_data, direct_deserialize_err, api_resp_deserialize_err
78                                )),
79                                data: None,
80                            }
81                        }
82                    }
83                }
84            }
85        } else {
86            match serde_json::from_value::<ApiResponse<T>>(raw_data.clone()) {
87                Ok(mut api_resp) => {
88                    if api_resp.success {
89                        api_resp.success = false;
90                        api_resp.error = api_resp.error.or_else(|| {
91                            raw_data["message"].as_str().map(|s| s.to_string())
92                        }).or_else(|| {
93                            Some(format!("API hatası (HTTP {}): API yanıtında 'success' true ancak HTTP durum kodu hata. Yanıt: {:?}", status.as_u16(), raw_data))
94                        });
95                        api_resp.data = None;
96                    }
97                    api_resp
98                },
99                Err(e) => {
100                    let error_message = raw_data["error"].as_str()
101                        .or(raw_data["message"].as_str())
102                        .map(|s| s.to_string())
103                        .unwrap_or_else(|| {
104                            format!("API hatası (HTTP {}): JSON formatı beklenenden farklı veya ayrıştırma hatası. Yanıt: {:?} - Hata: {}",
105                                    status.as_u16(), raw_data, e)
106                        });
107                    ApiResponse {
108                        success: false,
109                        error: Some(error_message),
110                        data: None,
111                    }
112                }
113            }
114        };
115
116        Ok(final_api_response)
117    }
118}