bw_web_api_rs/
client.rs

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}