stripe_rs/
error.rs

1use curl;
2use rustc_serialize::json::{Json, ParserError};
3use std::convert::From;
4use std::error::Error as StdError;
5use std::fmt;
6use std::str::Utf8Error;
7
8pub enum ErrorKind {
9	InvalidRequestError,
10	APIError,
11	CardError,
12	ConnectionError,
13	AuthentificationError,
14}
15
16pub enum ErrorCode {
17	IncorrectNumber,
18	InvalidNumber,
19	InvalidExpiryMonth,
20	InvalidExpiryYear,
21	InvalidCVC,
22	ExpiredCard,
23	IncorrectCVC,
24	IncorrectZIP,
25	CardDeclined,
26	Missing,
27	ProcessingError,
28	RateLimit,
29	Unknown,
30}
31
32pub struct Error {
33	kind: ErrorKind,
34	code: Option<ErrorCode>,
35	param: Option<String>,
36	message: Option<String>,
37}
38
39impl Error {
40	pub fn new(kind: ErrorKind, message: &str) -> Self {
41		Error { kind: kind, code: None, param: None, message: Some(message.to_string()) }
42	}
43
44	pub fn from_json(obj: &Json, http_status: u32) -> Self {
45		let kind = match http_status {
46			401 => ErrorKind::AuthentificationError,
47			_ => obj.find("type").map_or(ErrorKind::APIError, |t|
48				match &*t.to_string() {
49					"invalid_request_error" => ErrorKind::InvalidRequestError,
50					"card_error" => ErrorKind::CardError,
51					"api_error" | _ => ErrorKind::APIError,
52				}
53			),
54		};
55		let code = obj.find("code").and_then(|c|
56			Some(match &*c.to_string() {
57				"incorrect_number" => ErrorCode::IncorrectNumber,
58				"invalid_number" => ErrorCode::InvalidNumber,
59				"invalid_expiry_month" => ErrorCode::InvalidExpiryMonth,
60				"invalid_expiry_year" => ErrorCode::InvalidExpiryYear,
61				"invalid_cvc" => ErrorCode::InvalidCVC,
62				"expired_card" => ErrorCode::ExpiredCard,
63				"incorrect_cvc" => ErrorCode::IncorrectCVC,
64				"incorrect_zip" => ErrorCode::IncorrectZIP,
65				"card_declined" => ErrorCode::CardDeclined,
66				"missing" => ErrorCode::Missing,
67				"processing_error" => ErrorCode::ProcessingError,
68				"rate_limit" => ErrorCode::RateLimit,
69				_ => ErrorCode::Unknown
70			})
71		);
72		let param = obj.find("param").and_then(|p| Some(p.to_string()));
73		let message = obj.find("message").and_then(|m| Some(m.to_string()));
74		Error { kind: kind, code: code, param: param, message: message }
75	}
76}
77
78impl StdError for Error {
79	fn description(&self) -> &str {
80		self.message.as_ref().map_or("Stripe error", |m| &m)
81	}
82}
83
84impl fmt::Debug for Error {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        self.description().fmt(f)
87    }
88}
89
90impl fmt::Display for Error {
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        fmt::Debug::fmt(&self, f)
93    }
94}
95
96impl From<curl::ErrCode> for Error {
97	#[allow(unused_variables)]
98	fn from(err: curl::ErrCode) -> Self {
99		Error::new(ErrorKind::ConnectionError, "Network communication failed")
100	}
101}
102
103impl From<Utf8Error> for Error {
104	#[allow(unused_variables)]
105	fn from(err: Utf8Error) -> Self {
106		Error::new(ErrorKind::APIError, "Response is not valid UTF-8")
107	}
108}
109
110impl From<ParserError> for Error {
111	#[allow(unused_variables)]
112	fn from(err: ParserError) -> Self {
113		Error::new(ErrorKind::APIError, "Response is not valid JSON")
114	}
115}