bw-web-api-rs 0.2.8

A Rust client for the StarCraft: Remastered API
Documentation
use reqwest::Client;
use serde::{de::DeserializeOwned, Serialize};
use std::time::Duration;

use crate::config::ApiConfig;
use crate::endpoints::Endpoint;
use crate::error::ApiError;

pub struct ApiClient {
    client: reqwest::Client,
    config: ApiConfig,
}

impl ApiClient {
    pub fn new(config: ApiConfig) -> Result<Self, ApiError> {
        let client = Client::builder()
            .timeout(Duration::from_secs(30))
            .build()
            .map_err(|e| ApiError::ClientCreationError(e.to_string()))?;

        Ok(Self { client, config })
    }

    pub async fn request<E>(
        &self,
        endpoint: &E,
        params: &E::Request,
    ) -> Result<E::Response, ApiError>
    where
        E: Endpoint,
        E::Request: Serialize,
        E::Response: DeserializeOwned,
    {
        let url = format!("{}{}", self.config.base_url, endpoint.endpoint());

        let mut request_builder = self.client.get(&url);
        request_builder = request_builder.header("Accept", "application/json");

        if let Some(ref api_key) = self.config.api_key {
            request_builder = request_builder.header("x-api-key", format!("Bearer {}", api_key));
        }

        let response = request_builder.query(params).send().await?;

        if !response.status().is_success() {
            return Err(ApiError::ApiError {
                status: response.status().as_u16(),
                message: response.text().await.unwrap_or_default(),
            });
        }

        let text = response.text().await?;

        serde_json::from_str(&text).map_err(|e| {
            ApiError::DeserializationError(format!(
                "Failed to deserialize: {}. Response starts with: {}",
                e,
                &text[..text.len().min(200)]
            ))
        })
    }
}