inth_oauth2_async/
error.rs1use std::error::Error;
4use std::fmt;
5
6use serde_json::Value;
7
8use crate::client::response::{FromResponse, ParseError};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum OAuth2ErrorCode {
15 InvalidRequest,
19
20 InvalidClient,
23
24 InvalidGrant,
28
29 UnauthorizedClient,
31
32 UnsupportedGrantType,
34
35 InvalidScope,
38
39 Unrecognized(String),
41}
42
43impl<'a> From<&'a str> for OAuth2ErrorCode {
44 fn from(s: &str) -> OAuth2ErrorCode {
45 match s {
46 "invalid_request" => OAuth2ErrorCode::InvalidRequest,
47 "invalid_client" => OAuth2ErrorCode::InvalidClient,
48 "invalid_grant" => OAuth2ErrorCode::InvalidGrant,
49 "unauthorized_client" => OAuth2ErrorCode::UnauthorizedClient,
50 "unsupported_grant_type" => OAuth2ErrorCode::UnsupportedGrantType,
51 "invalid_scope" => OAuth2ErrorCode::InvalidScope,
52 s => OAuth2ErrorCode::Unrecognized(s.to_owned()),
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct OAuth2Error {
62 pub code: OAuth2ErrorCode,
64
65 pub description: Option<String>,
67
68 pub uri: Option<String>,
70}
71
72impl fmt::Display for OAuth2Error {
73 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
74 write!(f, "{:?}", self.code)?;
75 if let Some(ref description) = self.description {
76 write!(f, ": {}", description)?;
77 }
78 if let Some(ref uri) = self.uri {
79 write!(f, " ({})", uri)?;
80 }
81 Ok(())
82 }
83}
84
85impl Error for OAuth2Error {
86 fn description(&self) -> &str { "OAuth 2.0 API error" }
87}
88
89impl FromResponse for OAuth2Error {
90 fn from_response(json: &Value) -> Result<Self, ParseError> {
91 let obj = json.as_object().ok_or(ParseError::ExpectedType("object"))?;
92
93 let code = obj.get("error")
94 .and_then(Value::as_str)
95 .ok_or(ParseError::ExpectedFieldType("error", "string"))?;
96 let description = obj.get("error_description").and_then(Value::as_str);
97 let uri = obj.get("error_uri").and_then(Value::as_str);
98
99 Ok(OAuth2Error {
100 code: code.into(),
101 description: description.map(Into::into),
102 uri: uri.map(Into::into),
103 })
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn from_response_empty() {
113 let json = "{}".parse().unwrap();
114 assert_eq!(
115 ParseError::ExpectedFieldType("error", "string"),
116 OAuth2Error::from_response(&json).unwrap_err()
117 );
118 }
119
120 #[test]
121 fn from_response() {
122 let json = r#"{"error":"invalid_request"}"#.parse().unwrap();
123 assert_eq!(
124 OAuth2Error {
125 code: OAuth2ErrorCode::InvalidRequest,
126 description: None,
127 uri: None,
128 },
129 OAuth2Error::from_response(&json).unwrap()
130 );
131 }
132
133 #[test]
134 fn from_response_with_description() {
135 let json = r#"{"error":"invalid_request","error_description":"foo"}"#
136 .parse()
137 .unwrap();
138 assert_eq!(
139 OAuth2Error {
140 code: OAuth2ErrorCode::InvalidRequest,
141 description: Some(String::from("foo")),
142 uri: None,
143 },
144 OAuth2Error::from_response(&json).unwrap()
145 );
146 }
147
148 #[test]
149 fn from_response_with_uri() {
150 let json = r#"{"error":"invalid_request","error_uri":"http://example.com"}"#
151 .parse()
152 .unwrap();
153 assert_eq!(
154 OAuth2Error {
155 code: OAuth2ErrorCode::InvalidRequest,
156 description: None,
157 uri: Some(String::from("http://example.com")),
158 },
159 OAuth2Error::from_response(&json).unwrap()
160 );
161 }
162}