1use reqwest::Client;
2use serde::{de::DeserializeOwned, Serialize};
3use std::time::Duration;
4
5use crate::config::ApiConfig;
6use crate::endpoints::Endpoint;
7use crate::error::ApiError;
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>(
25 &self,
26 endpoint: &E,
27 params: &E::Request,
28 ) -> Result<E::Response, ApiError>
29 where
30 E: Endpoint,
31 E::Request: Serialize,
32 E::Response: DeserializeOwned,
33 {
34 let url = format!("{}{}", self.config.base_url, endpoint.endpoint());
35
36 let mut request_builder = self.client.get(&url);
37 request_builder = request_builder.header("Accept", "application/json");
38
39 if let Some(ref api_key) = self.config.api_key {
40 request_builder = request_builder.header("x-api-key", format!("Bearer {}", api_key));
41 }
42
43 let response = request_builder.query(params).send().await?;
44
45 if !response.status().is_success() {
46 return Err(ApiError::ApiError {
47 status: response.status().as_u16(),
48 message: response.text().await.unwrap_or_default(),
49 });
50 }
51
52 let text = response.text().await?;
53
54 serde_json::from_str(&text).map_err(|e| {
55 ApiError::DeserializationError(format!(
56 "Failed to deserialize: {}. Response starts with: {}",
57 e,
58 &text[..text.len().min(200)]
59 ))
60 })
61 }
62}