sharesight-reqwest 0.1.0

A client that allows execution of sharesight-types using reqwest
Documentation
use std::borrow::Cow;

use log::warn;
use serde::de::DeserializeOwned;
use sharesight_types::ApiEndpoint;

pub struct Client<'a> {
    client: Cow<'a, reqwest::Client>,
}

impl Client<'_> {
    pub fn new() -> Client<'static> {
        Default::default()
    }

    pub async fn execute<'a, T: ApiEndpoint<'a>, U: DeserializeOwned>(
        &self,
        api_host: &'a str,
        access_token: &str,
        parameters: &'a T::Parameters,
    ) -> Result<U, SharesightReqwestError> {
        let client = self.client.as_ref();
        let resp = client
            .get(T::url(api_host, parameters).to_string())
            .bearer_auth(access_token)
            .json(parameters)
            .send()
            .await?;

        if resp.status().is_success() {
            let full = resp.bytes().await?;

            Ok(serde_json::from_slice(&full).map_err(|e| {
                if let Ok(s) = std::str::from_utf8(&full) {
                    warn!("Error deserializing json: {:?}\n{}", e, s);
                } else {
                    warn!("Error deserializing json - not valid utf-8: {:?}", e);
                }
                e
            })?)
        } else {
            Err(SharesightReqwestError::Http(resp))
        }
    }
}

impl AsRef<reqwest::Client> for Client<'_> {
    fn as_ref(&self) -> &reqwest::Client {
        self.client.as_ref()
    }
}

impl Default for Client<'_> {
    fn default() -> Self {
        Client {
            client: Cow::Owned(reqwest::Client::new()),
        }
    }
}

#[derive(Debug, thiserror::Error)]
pub enum SharesightReqwestError {
    #[error("Http request returned non-success status code\n{0:?}")]
    Http(reqwest::Response),
    #[error("Http error occurred\n{0:?}")]
    Reqwest(#[from] reqwest::Error),
    #[error("Deserialize error occurred\n{0:?}")]
    Deserialize(#[from] serde_json::Error),
}