1use std::io::Error as IoError;
3use std::time::Duration;
4
5use error_chain::*;
6use http::StatusCode;
7use reqwest::Error as ReqwestError;
8use serde::Deserialize;
9use serde_json::error::Error as SerdeError;
10use url::ParseError;
11
12
13error_chain! {
14 errors {
15 #[doc = "Client side error returned for faulty requests"]
16 Fault {
17 code: StatusCode,
18 error: ClientError,
19 } {
20 display("{}: '{}'", code, error.message)
21 description(error.message.as_str())
22 }
23 #[doc = "Error kind returned when a credential's rate limit has been exhausted. Wait for the reset duration before issuing more requests"]
24 RateLimit {
25 reset: Duration
26 } {
27 display("Rate limit exhausted. Will reset in {} seconds", reset.as_secs())
28 }
29 }
30 foreign_links {
31 Codec(SerdeError);
32 Reqwest(ReqwestError);
33 Url(ParseError);
34 IO(IoError);
35 }
36}
37
38#[derive(Debug, Deserialize, PartialEq)]
41pub struct FieldErr {
42 pub resource: String,
43 pub field: Option<String>,
44 pub code: String,
45 pub message: Option<String>,
46 pub documentation_url: Option<String>,
47}
48
49#[derive(Debug, Deserialize, PartialEq)]
50pub struct ClientError {
51 pub message: String,
52 pub errors: Option<Vec<FieldErr>>,
53 pub documentation_url: Option<String>,
54}
55
56#[cfg(test)]
57mod tests {
58 use super::{ClientError, FieldErr};
59 use serde_json;
60 #[test]
61 fn deserialize_client_field_errors() {
62 for (json, expect) in vec![
63 (
65 r#"{"message": "Validation Failed","errors":
66 [{
67 "resource": "Release",
68 "code": "custom",
69 "message": "Published releases must have a valid tag"
70 }]}"#,
71 ClientError {
72 message: "Validation Failed".to_owned(),
73 errors: Some(vec![FieldErr {
74 resource: "Release".to_owned(),
75 code: "custom".to_owned(),
76 field: None,
77 message: Some(
78 "Published releases \
79 must have a valid tag"
80 .to_owned(),
81 ),
82 documentation_url: None,
83 }]),
84 documentation_url: None,
85 },
86 ),
87 ] {
88 assert_eq!(serde_json::from_str::<ClientError>(json).unwrap(), expect);
89 }
90 }
91
92 #[test]
93 fn deserialize_client_top_level_documentation_url() {
94 let json = serde_json::json!({
95 "message": "Not Found",
96 "documentation_url": "https://developer.github.com/v3/activity/watching/#set-a-repository-subscription"
97 });
98 let expect = ClientError {
99 message: String::from("Not Found"),
100 errors: None,
101 documentation_url: Some(String::from(
102 "https://developer.github.com/v3/activity/watching/#set-a-repository-subscription",
103 )),
104 };
105 assert_eq!(serde_json::from_value::<ClientError>(json).unwrap(), expect)
106 }
107}