rustbasic-core 0.1.23

Core framework logic for RustBasic - A modern web framework for Rust
Documentation
use std::time::Duration;
use serde::Serialize;
use serde::de::DeserializeOwned;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};

pub struct Http;

pub struct PendingRequest {
    method: reqwest::Method,
    url: String,
    headers: HeaderMap,
    query: Option<serde_json::Value>,
    json_body: Option<serde_json::Value>,
    timeout: Option<Duration>,
}

pub struct Response {
    inner: reqwest::Response,
}

impl Http {
    pub fn get(url: &str) -> PendingRequest {
        PendingRequest::new(reqwest::Method::GET, url)
    }

    pub fn post(url: &str) -> PendingRequest {
        PendingRequest::new(reqwest::Method::POST, url)
    }

    pub fn put(url: &str) -> PendingRequest {
        PendingRequest::new(reqwest::Method::PUT, url)
    }

    pub fn patch(url: &str) -> PendingRequest {
        PendingRequest::new(reqwest::Method::PATCH, url)
    }

    pub fn delete(url: &str) -> PendingRequest {
        PendingRequest::new(reqwest::Method::DELETE, url)
    }
}

impl PendingRequest {
    pub fn new(method: reqwest::Method, url: &str) -> Self {
        Self {
            method,
            url: url.to_string(),
            headers: HeaderMap::new(),
            query: None,
            json_body: None,
            timeout: None,
        }
    }

    pub fn with_headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
        for (k, v) in headers {
            if let (Ok(hname), Ok(hval)) = (HeaderName::from_bytes(k.as_bytes()), HeaderValue::from_str(&v)) {
                self.headers.insert(hname, hval);
            }
        }
        self
    }

    pub fn header(mut self, key: &str, value: &str) -> Self {
        if let (Ok(hname), Ok(hval)) = (HeaderName::from_bytes(key.as_bytes()), HeaderValue::from_str(value)) {
            self.headers.insert(hname, hval);
        }
        self
    }

    pub fn with_token(self, token: &str) -> Self {
        self.header("Authorization", &format!("Bearer {}", token))
    }

    pub fn basic_auth(self, username: &str, password: Option<&str>) -> Self {
        let auth_str = format!("{}:{}", username, password.unwrap_or(""));
        let encoded = crate::base64::encode(auth_str.as_bytes());
        self.header("Authorization", &format!("Basic {}", encoded))
    }

    pub fn query(mut self, query: impl Serialize) -> Self {
        self.query = Some(serde_json::to_value(query).unwrap_or(serde_json::Value::Null));
        self
    }

    pub fn json(mut self, body: impl Serialize) -> Self {
        self.json_body = Some(serde_json::to_value(body).unwrap_or(serde_json::Value::Null));
        self
    }

    pub fn timeout(mut self, duration: Duration) -> Self {
        self.timeout = Some(duration);
        self
    }

    pub async fn send(self) -> Result<Response, reqwest::Error> {
        let mut client_builder = reqwest::Client::builder();
        if let Some(t) = self.timeout {
            client_builder = client_builder.timeout(t);
        }
        let client = client_builder.build()?;

        let mut req_builder = client.request(self.method, &self.url);
        req_builder = req_builder.headers(self.headers);

        if let Some(q) = self.query {
            req_builder = req_builder.query(&q);
        }

        if let Some(b) = self.json_body {
            req_builder = req_builder.json(&b);
        }

        let resp = req_builder.send().await?;
        Ok(Response { inner: resp })
    }
}

impl Response {
    pub fn status(&self) -> reqwest::StatusCode {
        self.inner.status()
    }

    pub fn is_success(&self) -> bool {
        self.inner.status().is_success()
    }

    pub async fn text(self) -> Result<String, reqwest::Error> {
        self.inner.text().await
    }

    pub async fn json<T: DeserializeOwned>(self) -> Result<T, reqwest::Error> {
        self.inner.json::<T>().await
    }

    pub async fn json_value(self) -> Result<serde_json::Value, reqwest::Error> {
        self.inner.json::<serde_json::Value>().await
    }
}