1use reqwest::Client;
2use serde::{de::DeserializeOwned, Serialize};
3use std::time::Duration;
4
5use crate::config::ApiConfig;
6use crate::error::ApiError;
7use crate::endpoints::Endpoint;
8
9pub struct ApiClient {
10 client: reqwest::Client,
11 config: ApiConfig,
12}
13
14impl ApiClient {
15 pub fn new(config: ApiConfig) -> Result<Self, ApiError> {
16 let client = Client::builder()
17 .timeout(Duration::from_secs(30))
18 .build()
19 .map_err(|e| ApiError::ClientCreationError(e.to_string()))?;
20
21 Ok(Self { client, config })
22 }
23
24 pub async fn request<E>(&self, endpoint: &E, params: &E::Request) -> Result<E::Response, ApiError>
25 where
26 E: Endpoint,
27 E::Request: Serialize,
28 E::Response: DeserializeOwned,
29 {
30 let url = format!("{}{}", self.config.base_url, endpoint.endpoint());
31
32 let mut request_builder = self.client.get(&url);
33 request_builder = request_builder.header("Accept", "application/json");
34
35 if let Some(ref api_key) = self.config.api_key {
36 request_builder = request_builder.header("x-api-key", format!("Bearer {}", api_key));
37 }
38
39 let response = request_builder
40 .query(params)
41 .send()
42 .await?;
43
44 if !response.status().is_success() {
45 return Err(ApiError::ApiError {
46 status: response.status().as_u16(),
47 message: response.text().await.unwrap_or_default(),
48 });
49 }
50
51 let text = response.text().await?;
52
53 serde_json::from_str(&text)
54 .map_err(|e| ApiError::DeserializationError(
55 format!("Failed to deserialize: {}. Response starts with: {}",
56 e,
57 &text[..text.len().min(200)]
58 )
59 ))
60 }
61}