reka 0.1.0

Async Rust SDK for the Reka API.
Documentation
use reqwest::header::{HeaderName, HeaderValue};
use serde::de::DeserializeOwned;

use crate::ClientConfig;
use crate::config::ServiceBase;
use crate::error::{ApiErrorResponse, ConfigError, RekaError, Result};
use crate::transport::request::RequestBuilder;
use crate::transport::sse;

#[derive(Clone)]
pub(crate) struct HttpTransport {
    client: reqwest::Client,
}

impl HttpTransport {
    pub(crate) fn new(config: &ClientConfig) -> Result<Self> {
        let mut default_headers = config.default_headers.clone();
        let api_key =
            HeaderValue::from_str(&config.api_key).map_err(ConfigError::InvalidApiKeyHeader)?;
        default_headers.insert(HeaderName::from_static("x-api-key"), api_key);

        let client = reqwest::Client::builder()
            .default_headers(default_headers)
            .user_agent(config.user_agent.clone())
            .timeout(config.timeout)
            .connect_timeout(config.connect_timeout)
            .build()
            .map_err(crate::Client::map_transport_error)?;

        Ok(Self { client })
    }

    pub(crate) fn request(
        &self,
        config: &ClientConfig,
        service: ServiceBase,
        method: reqwest::Method,
        path: impl Into<String>,
    ) -> RequestBuilder {
        let path = path.into();
        let url = config.endpoint_url(service, &path);
        RequestBuilder::new(self.client.request(method, url), path)
    }
}

pub(crate) async fn parse_json_response<T>(response: reqwest::Response, path: String) -> Result<T>
where
    T: DeserializeOwned,
{
    let status = response.status();
    let headers = response.headers().clone();
    let body = response
        .text()
        .await
        .map_err(crate::Client::map_transport_error)?;

    if !status.is_success() {
        let api_error = serde_json::from_str::<ApiErrorResponse>(&body).ok();
        return Err(RekaError::http_status(
            status, path, body, api_error, headers,
        ));
    }

    serde_json::from_str(&body).map_err(|source| RekaError::decode(path, body, source))
}

pub(crate) async fn parse_sse_response(
    response: reqwest::Response,
    path: String,
) -> Result<sse::EventStream> {
    let status = response.status();
    let headers = response.headers().clone();

    if !status.is_success() {
        let body = response
            .text()
            .await
            .map_err(crate::Client::map_transport_error)?;
        let api_error = serde_json::from_str::<ApiErrorResponse>(&body).ok();
        return Err(RekaError::http_status(
            status, path, body, api_error, headers,
        ));
    }

    Ok(sse::decode(response.bytes_stream()))
}