libstripe 0.5.9

Stripe library for rust.
Documentation
use crate::error::{self, Error};
use reqwest::header::{AUTHORIZATION, USER_AGENT};

#[cfg(not(feature = "async"))]
use reqwest::{
    Client as HttpClient,
    multipart::Form,
};

#[cfg(feature = "async")]
use reqwest::{
    r#async::Client as HttpClient,
    multipart::Form
};

#[cfg(feature = "async")]
use futures::{
    future::Future,
    stream::Stream
};

#[cfg(feature = "async")]
use std::{
    io::{self, Cursor}
};

use reqwest::Method;

use crate::resources::common::path::{UrlPath};
use crate::{Result};

#[derive(Clone)]
pub struct Client {
    key: String,
    account: Option<String>,
    idempotency: Option<String>,
}

impl Default for Client {
    fn default() -> Self {
        Client {
            key: String::new(),
            account: None,
            idempotency: None,
        }
    }
}

impl Client {
    pub fn new<S: AsRef<str>>(api_key: S) -> Client {
        let mut client = Client::default();
        client.stripe_key(api_key);
        client
    }

    pub fn stripe_key<S: AsRef<str>>(&mut self, key: S) {
        self.key = key.as_ref().into();
    }

    pub fn stripe_account(&mut self, acct: &str) {
        self.account = Some(acct.to_string());
    }

    pub fn idempotency(&mut self, key: &str) {
        self.idempotency = Some(key.to_string());
    }

    pub fn get<A, B>(&self, path: UrlPath, param: Vec<&str>, data: B) -> Result<A>
    where
        A: serde::de::DeserializeOwned + Send + 'static,
        B: serde::Serialize,
    {
        self.request(Method::GET, path, param, data, None)
    }

    pub fn post<A, B>(&self, path: UrlPath, param: Vec<&str>, data: B) -> Result<A>
    where
        A: serde::de::DeserializeOwned + Send + 'static,
        B: serde::Serialize,
    {
        self.request(Method::POST, path, param, data, None)
    }

    pub fn delete<A, B>(&self, path: UrlPath, param: Vec<&str>, data: B) -> Result<A>
    where
        A: serde::de::DeserializeOwned + Send + 'static,
        B: serde::Serialize,
    {
        self.request(Method::DELETE, path, param, data, None)
    }

    #[cfg(not(feature = "async"))]
    pub fn upload<A, B>(&self, path: UrlPath, param: Vec<&str>, data: B, form: Form) -> Result<A>
    where
        A: serde::de::DeserializeOwned + Send + 'static,
        B: serde::Serialize,
    {
        self.request(Method::POST, path, param, data, Some(form))
    }

    #[cfg(not(feature = "async"))]
    pub fn request<A, B>(
        &self,
        method: Method,
        path: UrlPath,
        param: Vec<&str>,
        data: B,
        form: Option<Form>,
    ) -> Result<A>
    where
        A: serde::de::DeserializeOwned + Send + 'static,
        B: serde::Serialize,
    {
        let mut param = param
                .iter()
                .map(|s| s.to_string())
                .collect::<Vec<String>>()
                .join("/");

        if param.len() > 0 {
            param = format!("/{}", param);
        }

        let uri = match path {
            UrlPath::File(true) => format!("https://files.stripe.com/v1{}{}", path, param),
            _ => format!("https://api.stripe.com/v1{}{}", path, param),
        };

        let client = HttpClient::new();
        let query = serde_qs::to_string(&data)?;
        let mut req = client
            .request(method, &uri)
            .body(query)
            .header(AUTHORIZATION, format!("Bearer {}", self.key))
            .header(USER_AGENT, "libstripe-rs/(crates.io/crates/libstripe)");

        if let Some(account) = self.account.clone() {
            req = req.header("Stripe-Account", account);
        }

        if let Some(idemp) = self.idempotency.clone() {
            req = req.header("Idempotency-Key", idemp);
        }

        if let Some(multipart) = form {
            req = req.multipart(multipart);
        }

        req.send().map_err(Error::from).and_then(|mut res| {
            if res.status().is_success() {
                res.json().map_err(Error::from)
            } else {
                let err: error::StripeErrorObject =
                    res.json().map_err(|e| error::StripeErrorObject {
                        error: error::StripeRequestObject {
                            error_type: error::ErrorType::Unknown,
                            message: Some(format!("{}", e)),
                            ..Default::default()
                        },
                    })?;
                Err(Error::from(err))
            }
        })
    }

    #[cfg(feature = "async")]
    pub fn request<A, B>(
        &self,
        method: Method,
        path: UrlPath,
        param: Vec<&str>,
        data: B,
        _form: Option<Form>,
    ) -> Result<A>
        where
            A: serde::de::DeserializeOwned + Send + 'static,
            B: serde::Serialize,
    {
        let mut param = param
            .iter()
            .map(|s| s.to_string())
            .collect::<Vec<String>>()
            .join("/");

        if param.len() > 0 {
            param = format!("/{}", param);
        }

        let uri = match path {
            UrlPath::File(true) => format!("https://files.stripe.com/v1{}{}", path, param),
            _ => format!("https://api.stripe.com/v1{}{}", path, param),
        };

        let client = HttpClient::new();
        let query = serde_qs::to_string(&data).unwrap_or_default();
        let mut req = client
            .request(method, &uri)
            .body(query)
            .header(AUTHORIZATION, format!("Bearer {}", self.key))
            .header(USER_AGENT, "libstripe-rs/(crates.io/crates/libstripe)");

        if let Some(account) = self.account.clone() {
            req = req.header("Stripe-Account", account);
        }

        if let Some(idemp) = self.idempotency.clone() {
            req = req.header("Idempotency-Key", idemp);
        }

        Box::new(req.send().map_err(Error::from).and_then(|res| {
            let status = res.status();

            res.into_body().concat2().map_err(Error::from).and_then(move |body| {
                let mut body = Cursor::new(body);
                let mut buffer = Vec::new();

                io::copy(&mut body, &mut buffer)?;

                if status.is_success() {
                    serde_json::from_slice(&buffer).map_err(Error::from)
                } else {
                    let err: error::StripeErrorObject =
                        serde_json::from_slice(&buffer).unwrap_or_else(|e| error::StripeErrorObject {
                            error: error::StripeRequestObject {
                                error_type: error::ErrorType::Unknown,
                                message: Some(format!("{}", e)),
                                ..Default::default()
                            },
                        });
                    Err(Error::from(err))
                }
            })
        }))
    }
}