stripe_rs/
lib.rs

1#![allow(dead_code)]
2
3extern crate curl;
4extern crate rustc_serialize;
5extern crate url;
6
7use curl::http;
8use curl::http::handle::Method;
9use rustc_serialize::base64::{STANDARD, ToBase64};
10use rustc_serialize::json::Json;
11use std::fmt::Display;
12use std::str::from_utf8;
13use url::form_urlencoded::serialize;
14
15pub use error::{Error, ErrorKind};
16
17mod error;
18mod macros;
19
20pub mod resources {
21	mod account;
22	mod application_fees;
23	mod balance;
24	mod bitcoin_receivers;
25	mod charges;
26	mod coupons;
27	mod customers;
28	mod events;
29	mod file_uploads;
30	mod invoice_items;
31	mod invoices;
32	mod plans;
33	mod recipients;
34	mod tokens;
35	mod transfers;
36}
37
38const VERSION: &'static str = env!("CARGO_PKG_VERSION");
39
40const API_BASE: &'static str = "https://api.stripe.com";
41const BASE_PATH: &'static str = "/v1";
42const CONNECT_BASE: &'static str = "https://connect.stripe.com";
43const UPLOADS_BASE: &'static str = "https://uploads.stripe.com";
44
45pub static mut api_key: Option<*const str> = None;
46pub static mut api_version: Option<*const str> = None;
47
48pub fn set_api_key(val: &str) {
49	unsafe { api_key = Some(val) };
50}
51
52pub fn set_api_version(val: &str) {
53	unsafe { api_key = Some(val) };
54}
55
56pub struct Params<'a> {
57	pairs: Vec<(String, String)>,
58	content_type: &'a str,
59}
60
61impl<'a> Params<'a> {
62	pub fn new() -> Self {
63		// TODO: Handle file uploads.
64		Params { pairs: Vec::new(), content_type: "application/x-www-form-urlencoded" }
65	}
66
67	pub fn set<T>(&mut self, key: &str, val: T) where T: Display {
68		self.pairs.push((key.to_string(), val.to_string()));
69	}
70
71	fn to_body(&self) -> String {
72		serialize(self.pairs.iter().map(|&(ref n, ref v)| (&**n, &**v)))
73	}
74}
75
76pub type Response = Result<Json, Error>;
77
78fn request(method: Method, path: &str, params: Option<&Params>) -> Response {
79	let body = params.and_then(|b| Some(b.to_body()));
80	let mut handle = http::handle();
81	let mut req = match method {
82		Method::Get => handle.get(path),
83		Method::Post => handle.post(path, body.as_ref().map_or("", |b| &b))
84						      .content_type("application/x-www-form-urlencoded"),
85		Method::Delete => handle.delete(path),
86		_ => panic!("unknown method"),
87	};
88
89	unsafe {
90		let auth = match api_key {
91			Some(val) => format!("{}:", &*val).as_bytes().to_base64(STANDARD),
92			None => return Err(Error::new(ErrorKind::AuthentificationError,
93										  "No API Key provided")),
94		};
95		req = req.header("Authorization", &format!("Basic {}", auth))
96			 	 .header("Accept", "application/json")
97			 	 .header("User-Agent", &format!("Stripe{} RustBindings/{}", BASE_PATH, VERSION));
98	
99		if api_version.is_some() {
100			req = req.header("Stripe-Version", &*api_version.unwrap());
101		}
102
103		// TODO: What about X-Stripe-Client-User-Agent?
104	}
105
106	let resp = try!(req.exec());
107	let body = try!(from_utf8(resp.get_body()));
108	let result = try!(Json::from_str(body));
109
110	if let Some(val) = result.find("error") {
111		return Err(Error::from_json(val, resp.get_code()));
112	}
113
114	Ok(result)
115}