twitch_highway 0.0.2

Twitch Api reqest Http
Documentation
use std::{collections::HashMap, fmt};

use reqwest::StatusCode;
use serde::{de, Serialize};
use url::Url;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error(transparent)]
    GetError(#[from] reqwest::Error),
    #[error("Faile get emotes {0}")]
    GETAPIErorr(APIError),
}

#[derive(Debug)]
pub struct APIError {
    pub status: String,
    pub message: String,
}

impl fmt::Display for APIError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Failed get emotes")
    }
}

#[derive(Debug, PartialEq)]
pub struct APIBase {
    access_token: String,
    client_id: String,
    pub base_url: Url,
}

impl APIBase {
    pub fn new<T: Into<String>>(access_token: T, client_id: T, base_url: T) -> APIBase {
        APIBase {
            access_token: access_token.into(),
            client_id: client_id.into(),
            base_url: Url::parse(&base_url.into()).unwrap(),
        }
    }

    pub async fn api_request_text<T: Into<String>>(&self, url: T) -> Result<String> {
        let req = reqwest::Client::new()
            .get(url.into())
            .header("Authorization", self.header_auth())
            .header("Client-Id", &self.client_id)
            .send()
            .await?;

        let status = req.status();

        match status {
            StatusCode::OK => Ok(req.text().await?),
            _ => Err(Error::GETAPIErorr(APIError {
                status: status.to_string(),
                message: req.text().await?,
            })),
        }
    }

    pub async fn api_request_json<T: Into<String>, S: de::DeserializeOwned>(
        &self,
        url: T,
    ) -> Result<S> {
        let req = reqwest::Client::new()
            .get(url.into())
            .header("Authorization", self.header_auth())
            .header("Client-Id", &self.client_id)
            .send()
            .await?;

        let status = req.status();

        match status {
            StatusCode::OK => Ok(req.json().await?),
            _ => Err(Error::GETAPIErorr(APIError {
                status: status.to_string(),
                message: req.text().await?,
            })),
        }
    }

    pub async fn api_post<T: Into<String>, I: Serialize>(
        &self,
        url: T,
        body: &I,
    ) -> Result<String> {
        let req = reqwest::Client::new()
            .post(url.into())
            .header("Authorization", self.header_auth())
            .header("Client-Id", &self.client_id)
            .header("Content-Type", "application/json")
            .json(body)
            .send()
            .await?;

        let status = req.status();

        match status {
            StatusCode::OK => Ok(req.text().await?),
            _ => Err(Error::GETAPIErorr(APIError {
                status: status.to_string(),
                message: req.text().await?,
            })),
        }
    }

    pub async fn api_post_json<T: Into<String>, I: Serialize, S: de::DeserializeOwned>(
        &self,
        url: T,
        body: &I,
    ) -> Result<S> {
        let req = reqwest::Client::new()
            .post(url.into())
            .header("Authorization", self.header_auth())
            .header("Client-Id", &self.client_id)
            .header("Content-Type", "application/json")
            .json(body)
            .send()
            .await?;

        let status = req.status();

        match status {
            StatusCode::OK => Ok(req.json().await?),
            _ => Err(Error::GETAPIErorr(APIError {
                status: status.to_string(),
                message: req.text().await?,
            })),
        }
    }

    pub async fn api_delete<T: Into<String>>(&self, url: T) -> Result<String> {
        let req = reqwest::Client::new()
            .delete(url.into())
            .header("Authorization", self.header_auth())
            .header("Client-Id", &self.client_id)
            .send()
            .await?;

        let status = req.status();

        match status {
            StatusCode::OK => Ok(req.text().await?),
            _ => Err(Error::GETAPIErorr(APIError {
                status: status.to_string(),
                message: req.text().await?,
            })),
        }
    }

    fn header_auth(&self) -> String {
        format!("Bearer {}", &self.access_token)
    }

    pub fn url(&self) -> String {
        format!("{}", self.base_url)
    }

    pub fn url_endpoint<T: Into<String>>(&self, endpoint: T) -> String {
        format!("{}/{}", self.base_url, endpoint.into())
    }

    pub fn url_qurey<T: Into<String>>(&self, key: T, value: T) -> String {
        format!(
            "{}?{}",
            self.base_url,
            self.set_query(vec![(key.into(), value.into())])
        )
    }
    pub fn url_qureys<T: Into<String>>(&self, query: Vec<(T, T)>) -> String {
        format!("{}?{}", self.base_url, self.set_query(query))
    }

    pub fn url_endpoint_qurey<T: Into<String>>(&self, endpoint: T, key: T, value: T) -> String {
        format!(
            "{}/{}?{}",
            self.base_url,
            endpoint.into(),
            self.set_query(vec![(key.into(), value.into())])
        )
    }

    pub fn url_endpoint_qureys<T: Into<String>>(
        &self,
        endpoint: T,
        query: Vec<(&str, &str)>,
    ) -> String {
        format!(
            "{}/{}?{}",
            self.base_url,
            endpoint.into(),
            self.set_query(query)
        )
    }

    fn set_query<T: Into<String>>(&self, query: Vec<(T, T)>) -> String {
        query
            .into_iter()
            .map(|(key, value)| format!("{}={}", key.into(), value.into()))
            .collect::<Vec<String>>()
            .join("&")
    }
}

#[derive(Debug, Serialize)]
pub struct APIPostBoby {
    pub data: HashMap<String, String>,
}

impl APIPostBoby {
    pub fn new(data: HashMap<String, String>) -> APIPostBoby {
        APIPostBoby { data }
    }
}