1use serde::Serialize;
2use std::fmt::{Display, Formatter};
3
4#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
5pub struct InnerError {
6 #[serde(skip_serializing_if = "Option::is_none")]
7 pub code: Option<String>,
8 #[serde(rename = "request-id")]
9 #[serde(skip_serializing_if = "Option::is_none")]
10 pub request_id: Option<String>,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub date: Option<String>,
13}
14
15#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
20pub struct ErrorStatus {
21 #[serde(skip_serializing_if = "Option::is_none")]
24 pub code: Option<String>,
25
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub message: Option<String>,
29
30 #[serde(rename = "innerError")]
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub inner_error: Option<InnerError>,
34}
35
36#[derive(thiserror::Error, Debug)]
37pub enum HttpResponseErrorMessage {
38 #[error("{0:#?}")]
39 GraphErrorMessage(#[from] ErrorMessage),
40 #[error("{0:#?}")]
41 SerdeJsonError(#[from] serde_json::error::Error),
42 #[error("{0:#?}")]
43 ReqwestError(#[from] reqwest::Error),
44}
45
46#[derive(thiserror::Error, Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
47pub struct ErrorMessage {
48 pub error: ErrorStatus,
49}
50
51impl ErrorMessage {
52 pub fn message(&self) -> Option<String> {
53 self.error.message.clone()
54 }
55
56 pub fn code_property(&self) -> Option<String> {
57 self.error.code.clone()
58 }
59
60 pub fn detailed_error_code(&self) -> Option<String> {
61 self.error.inner_error.as_ref()?.code.clone()
62 }
63
64 pub fn inner_error(&self) -> Option<&InnerError> {
65 self.error.inner_error.as_ref()
66 }
67
68 pub fn request_id(&self) -> Option<String> {
69 self.error.inner_error.as_ref()?.request_id.clone()
70 }
71
72 pub fn date(&self) -> Option<String> {
73 self.error.inner_error.as_ref()?.date.clone()
74 }
75}
76
77impl Display for ErrorMessage {
78 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
79 write!(f, "({:#?})", self.error)
80 }
81}
82
83#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
85pub enum ErrorType {
86 BadRequest,
87 Unauthorized,
88 Forbidden,
89 NotFound,
90 MethodNotAllowed,
91 NotAcceptable,
92 Conflict,
93 Gone,
94 LengthRequired,
95 PreconditionFailed,
96 RequestEntityTooLarge,
97 UnsupportedMediaType,
98 RequestRangeNotSatisfiable,
99 UnprocessableEntity,
100 Locked,
101 TooManyRequests,
102 InternalServerError,
103 NotImplemented,
104 ServiceUnavailable,
105 GatewayTimeout,
106 InsufficientStorage,
107 BandwidthLimitExceeded,
108 UnknownError,
109}
110
111impl ErrorType {}
112
113impl ErrorType {
114 pub fn as_str(&self) -> &str {
115 match *self {
116 ErrorType::BadRequest => "Cannot process the request because it is malformed or incorrect.",
117 ErrorType::Unauthorized => "Required authentication information is either missing or not valid for the resource.",
118 ErrorType::Forbidden => "Access is denied to the requested resource. The user might not have enough permission.",
119 ErrorType::NotFound => "The requested resource doesnt exist.",
120 ErrorType::MethodNotAllowed => "The HTTP method in the request is not allowed on the resource.",
121 ErrorType::NotAcceptable => "This service doesnt support the format requested in the Accept header.",
122 ErrorType::Conflict =>
123 "The current state conflicts with what the request expects. For example, the specified parent folder might not exist",
124 ErrorType::Gone => "The requested resource is no longer available at the server.",
125 ErrorType::LengthRequired => "A Content-Length header is required on the request.",
126 ErrorType::PreconditionFailed =>
127 "A precondition provided in the request (such as an if-match header) does not match the resource's current state.",
128 ErrorType::RequestEntityTooLarge => "The request size exceeds the maximum limit.",
129 ErrorType::UnsupportedMediaType => "The content type of the request is a format that is not supported by the service.",
130 ErrorType::RequestRangeNotSatisfiable => "The specified byte range is invalid or unavailable.",
131 ErrorType::UnprocessableEntity => "Cannot process the request because it is semantically incorrect.",
132 ErrorType::Locked => "The resource that is being accessed is locked.",
133 ErrorType::TooManyRequests =>
134 "Client application has been throttled and should not attempt to repeat the request until an amount of time has elapsed.",
135 ErrorType::InternalServerError => "There was an internal server error while processing the request.",
136 ErrorType::NotImplemented => "The requested feature isn’t implemented.",
137 ErrorType::ServiceUnavailable =>
138 "The service is temporarily unavailable. You may repeat the request after a delay. There may be a Retry-After header.",
139 ErrorType::GatewayTimeout =>
140 "The server, while acting as a proxy, did not receive a timely response from the upstream server it needed to access in attempting to complete the request. May occur together with 503.",
141 ErrorType::InsufficientStorage => "The maximum storage quota has been reached.",
142 ErrorType::BandwidthLimitExceeded =>
143 "Your app has been throttled for exceeding the maximum bandwidth cap. Your app can retry the request again after more time has elapsed.",
144 ErrorType::UnknownError => "Unknown error or failure",
145 }
146 }
147
148 pub fn from_u16(num: u16) -> Option<ErrorType> {
149 match num {
150 400 => Some(ErrorType::BadRequest),
151 401 => Some(ErrorType::Unauthorized),
152 403 => Some(ErrorType::Forbidden),
153 404 => Some(ErrorType::NotFound),
154 405 => Some(ErrorType::MethodNotAllowed),
155 406 => Some(ErrorType::NotAcceptable),
156 409 => Some(ErrorType::Conflict),
157 410 => Some(ErrorType::Gone),
158 411 => Some(ErrorType::LengthRequired),
159 412 => Some(ErrorType::PreconditionFailed),
160 413 => Some(ErrorType::RequestEntityTooLarge),
161 415 => Some(ErrorType::UnsupportedMediaType),
162 416 => Some(ErrorType::RequestRangeNotSatisfiable),
163 422 => Some(ErrorType::UnprocessableEntity),
164 423 => Some(ErrorType::Locked),
165 429 => Some(ErrorType::TooManyRequests),
166 500 => Some(ErrorType::InternalServerError),
167 501 => Some(ErrorType::NotImplemented),
168 503 => Some(ErrorType::ServiceUnavailable),
169 504 => Some(ErrorType::GatewayTimeout),
170 507 => Some(ErrorType::InsufficientStorage),
171 509 => Some(ErrorType::BandwidthLimitExceeded),
172 _ => None,
173 }
174 }
175
176 pub fn is_error(status: u16) -> bool {
177 ErrorType::from_u16(status).is_some()
178 }
179}
180
181impl Display for ErrorType {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "{}", self.as_str())
184 }
185}