cdumay_http_client/
errors.rs

1use std::collections::BTreeMap;
2
3use cdumay_error::{ErrorBuilder, ErrorKind, GenericErrors};
4use serde_json::value::Value;
5
6#[derive(Debug)]
7pub struct ResponseErrorWithContext {
8    pub status: reqwest::StatusCode,
9    pub context: Option<BTreeMap<String, Value>>,
10}
11
12
13#[derive(Debug)]
14pub enum ClientError {
15    InternalError(String),
16    ParseError(String),
17    GenericHttpError(reqwest::Error),
18    UrlError(url::ParseError),
19    ResponseError(ResponseErrorWithContext),
20    InvalidHeaderName(reqwest::header::InvalidHeaderName),
21    InvalidHeaderValue(reqwest::header::InvalidHeaderValue),
22}
23
24impl From<ClientError> for ErrorBuilder {
25    fn from(value: ClientError) -> Self {
26        match value {
27            ClientError::InternalError(data) => ErrorBuilder::from(GenericErrors::UNKNOWN_ERROR).message(data),
28            ClientError::ParseError(data) => ErrorBuilder::from(GenericErrors::DESERIALIZATION_ERROR).message(data),
29            ClientError::GenericHttpError(err) => ErrorBuilder::from(HttpStatusCodeErrors::GENERIC_HTTP_CLIENT_ERROR).message(err.to_string()),
30            ClientError::UrlError(err) => ErrorBuilder::from(HttpStatusCodeErrors::INVALID_URL).message(err.to_string()),
31            ClientError::ResponseError(err) => {
32                match err.context {
33                    Some(context) => ErrorBuilder::from(HttpStatusCodeErrors::from_status(err.status)).extra(context.into()),
34                    None => ErrorBuilder::from(HttpStatusCodeErrors::from_status(err.status))
35                }
36            }
37            ClientError::InvalidHeaderName(err) => ErrorBuilder::from(GenericErrors::VALIDATION_ERROR).message(err.to_string()),
38            ClientError::InvalidHeaderValue(err) => ErrorBuilder::from(GenericErrors::VALIDATION_ERROR).message(err.to_string()),
39        }
40    }
41}
42
43impl From<reqwest::Error> for ClientError {
44    fn from(err: reqwest::Error) -> ClientError {
45        ClientError::GenericHttpError(err)
46    }
47}
48
49impl From<reqwest::header::InvalidHeaderName> for ClientError {
50    fn from(err: reqwest::header::InvalidHeaderName) -> ClientError {
51        ClientError::InvalidHeaderName(err)
52    }
53}
54
55impl From<reqwest::header::InvalidHeaderValue> for ClientError {
56    fn from(err: reqwest::header::InvalidHeaderValue) -> ClientError {
57        ClientError::InvalidHeaderValue(err)
58    }
59}
60
61impl From<reqwest::blocking::Response> for ClientError {
62    fn from(resp: reqwest::blocking::Response) -> ClientError {
63        ClientError::ResponseError(ResponseErrorWithContext {
64            status: resp.status(),
65            context: resp.json::<BTreeMap<String, Value>>().ok(),
66        })
67    }
68}
69
70
71pub struct HttpStatusCodeErrors;
72
73impl HttpStatusCodeErrors {
74    pub const INVALID_URL: ErrorKind = ErrorKind("Err-27071", 400, "Invalid url");
75    pub const GENERIC_HTTP_CLIENT_ERROR: ErrorKind = ErrorKind("Err-05192", 500, "Generic HTTP client error");
76    pub const MULTIPLE_CHOICES: ErrorKind = ErrorKind("Err-11298", 300, "Multiple Choices");
77    pub const MOVED_PERMANENTLY: ErrorKind = ErrorKind("Err-23108", 301, "Moved Permanently");
78    pub const FOUND: ErrorKind = ErrorKind("Err-07132", 302, "Found");
79    pub const SEE_OTHER: ErrorKind = ErrorKind("Err-16746", 303, "See Other");
80    pub const NOT_MODIFIED: ErrorKind = ErrorKind("Err-21556", 304, "Not Modified");
81    pub const USE_PROXY: ErrorKind = ErrorKind("Err-31839", 305, "Use Proxy");
82    pub const TEMPORARY_REDIRECT: ErrorKind = ErrorKind("Err-25446", 307, "Temporary Redirect");
83    pub const PERMANENT_REDIRECT: ErrorKind = ErrorKind("Err-12280", 308, "Permanent Redirect");
84    pub const BAD_REQUEST: ErrorKind = ErrorKind("Err-26760", 400, "Bad Request");
85    pub const UNAUTHORIZED: ErrorKind = ErrorKind("Err-08059", 401, "Unauthorized");
86    pub const PAYMENT_REQUIRED: ErrorKind = ErrorKind("Err-18076", 402, "Payment Required");
87    pub const FORBIDDEN: ErrorKind = ErrorKind("Err-23134", 403, "Forbidden");
88    pub const NOT_FOUND: ErrorKind = ErrorKind("Err-18430", 404, "Not Found");
89    pub const METHOD_NOT_ALLOWED: ErrorKind = ErrorKind("Err-23585", 405, "Method Not Allowed");
90    pub const NOT_ACCEPTABLE: ErrorKind = ErrorKind("Err-04289", 406, "Not Acceptable");
91    pub const PROXY_AUTHENTICATION_REQUIRED: ErrorKind = ErrorKind("Err-17336", 407, "Proxy Authentication Required");
92    pub const REQUEST_TIMEOUT: ErrorKind = ErrorKind("Err-00565", 408, "Request Timeout");
93    pub const CONFLICT: ErrorKind = ErrorKind("Err-08442", 409, "Conflict");
94    pub const GONE: ErrorKind = ErrorKind("Err-19916", 410, "Gone");
95    pub const LENGTH_REQUIRED: ErrorKind = ErrorKind("Err-09400", 411, "Length Required");
96    pub const PRECONDITION_FAILED: ErrorKind = ErrorKind("Err-22509", 412, "Precondition Failed");
97    pub const PAYLOAD_TOO_LARGE: ErrorKind = ErrorKind("Err-10591", 413, "Payload Too Large");
98    pub const URI_TOO_LONG: ErrorKind = ErrorKind("Err-01377", 414, "URI Too Long");
99    pub const UNSUPPORTED_MEDIA_TYPE: ErrorKind = ErrorKind("Err-12512", 415, "Unsupported Media Type");
100    pub const RANGE_NOT_SATISFIABLE: ErrorKind = ErrorKind("Err-21696", 416, "Range Not Satisfiable");
101    pub const EXPECTATION_FAILED: ErrorKind = ErrorKind("Err-16872", 417, "Expectation Failed");
102    pub const IM_A_TEAPOT: ErrorKind = ErrorKind("Err-23719", 418, "I'm a teapot");
103    pub const MISDIRECTED_REQUEST: ErrorKind = ErrorKind("Err-26981", 421, "Misdirected Request");
104    pub const UNPROCESSABLE_ENTITY: ErrorKind = ErrorKind("Err-12568", 422, "Unprocessable Entity");
105    pub const LOCKED: ErrorKind = ErrorKind("Err-32695", 423, "Locked");
106    pub const FAILED_DEPENDENCY: ErrorKind = ErrorKind("Err-19693", 424, "Failed Dependency");
107    pub const UPGRADE_REQUIRED: ErrorKind = ErrorKind("Err-22991", 426, "Upgrade Required");
108    pub const PRECONDITION_REQUIRED: ErrorKind = ErrorKind("Err-02452", 428, "Precondition Required");
109    pub const TOO_MANY_REQUESTS: ErrorKind = ErrorKind("Err-12176", 429, "Too Many Requests");
110    pub const REQUEST_HEADER_FIELDS_TOO_LARGE: ErrorKind = ErrorKind("Err-07756", 431, "Request Header Fields Too Large");
111    pub const UNAVAILABLE_FOR_LEGAL_REASONS: ErrorKind = ErrorKind("Err-12136", 451, "Unavailable For Legal Reasons");
112    pub const INTERNAL_SERVER_ERROR: ErrorKind = ErrorKind("Err-09069", 500, "Internal Server Error");
113    pub const NOT_IMPLEMENTED: ErrorKind = ErrorKind("Err-03394", 501, "Not Implemented");
114    pub const BAD_GATEWAY: ErrorKind = ErrorKind("Err-19734", 502, "Bad Gateway");
115    pub const SERVICE_UNAVAILABLE: ErrorKind = ErrorKind("Err-18979", 503, "Service Unavailable");
116    pub const GATEWAY_TIMEOUT: ErrorKind = ErrorKind("Err-17595", 504, "Gateway Timeout");
117    pub const HTTP_VERSION_NOT_SUPPORTED: ErrorKind = ErrorKind("Err-01625", 505, "HTTP Version Not Supported");
118    pub const VARIANT_ALSO_NEGOTIATES: ErrorKind = ErrorKind("Err-28382", 506, "Variant Also Negotiates");
119    pub const INSUFFICIENT_STORAGE: ErrorKind = ErrorKind("Err-32132", 507, "Insufficient Storage");
120    pub const LOOP_DETECTED: ErrorKind = ErrorKind("Err-30770", 508, "Loop Detected");
121    pub const NOT_EXTENDED: ErrorKind = ErrorKind("Err-19347", 510, "Not Extended");
122    pub const NETWORK_AUTHENTICATION_REQUIRED: ErrorKind = ErrorKind("Err-31948", 511, "Network Authentication Required");
123}
124
125impl HttpStatusCodeErrors {
126    pub fn from_status(status: http::StatusCode) -> ErrorKind {
127        match status {
128            http::StatusCode::MOVED_PERMANENTLY => HttpStatusCodeErrors::MOVED_PERMANENTLY,
129            http::StatusCode::FOUND => HttpStatusCodeErrors::FOUND,
130            http::StatusCode::SEE_OTHER => HttpStatusCodeErrors::SEE_OTHER,
131            http::StatusCode::NOT_MODIFIED => HttpStatusCodeErrors::NOT_MODIFIED,
132            http::StatusCode::USE_PROXY => HttpStatusCodeErrors::USE_PROXY,
133            http::StatusCode::TEMPORARY_REDIRECT => HttpStatusCodeErrors::TEMPORARY_REDIRECT,
134            http::StatusCode::PERMANENT_REDIRECT => HttpStatusCodeErrors::PERMANENT_REDIRECT,
135            http::StatusCode::BAD_REQUEST => HttpStatusCodeErrors::BAD_REQUEST,
136            http::StatusCode::UNAUTHORIZED => HttpStatusCodeErrors::UNAUTHORIZED,
137            http::StatusCode::PAYMENT_REQUIRED => HttpStatusCodeErrors::PAYMENT_REQUIRED,
138            http::StatusCode::FORBIDDEN => HttpStatusCodeErrors::FORBIDDEN,
139            http::StatusCode::NOT_FOUND => HttpStatusCodeErrors::NOT_FOUND,
140            http::StatusCode::METHOD_NOT_ALLOWED => HttpStatusCodeErrors::METHOD_NOT_ALLOWED,
141            http::StatusCode::NOT_ACCEPTABLE => HttpStatusCodeErrors::NOT_ACCEPTABLE,
142            http::StatusCode::PROXY_AUTHENTICATION_REQUIRED => HttpStatusCodeErrors::PROXY_AUTHENTICATION_REQUIRED,
143            http::StatusCode::REQUEST_TIMEOUT => HttpStatusCodeErrors::REQUEST_TIMEOUT,
144            http::StatusCode::CONFLICT => HttpStatusCodeErrors::CONFLICT,
145            http::StatusCode::GONE => HttpStatusCodeErrors::GONE,
146            http::StatusCode::LENGTH_REQUIRED => HttpStatusCodeErrors::LENGTH_REQUIRED,
147            http::StatusCode::PRECONDITION_FAILED => HttpStatusCodeErrors::PRECONDITION_FAILED,
148            http::StatusCode::PAYLOAD_TOO_LARGE => HttpStatusCodeErrors::PAYLOAD_TOO_LARGE,
149            http::StatusCode::URI_TOO_LONG => HttpStatusCodeErrors::URI_TOO_LONG,
150            http::StatusCode::UNSUPPORTED_MEDIA_TYPE => HttpStatusCodeErrors::UNSUPPORTED_MEDIA_TYPE,
151            http::StatusCode::RANGE_NOT_SATISFIABLE => HttpStatusCodeErrors::RANGE_NOT_SATISFIABLE,
152            http::StatusCode::EXPECTATION_FAILED => HttpStatusCodeErrors::EXPECTATION_FAILED,
153            http::StatusCode::IM_A_TEAPOT => HttpStatusCodeErrors::IM_A_TEAPOT,
154            http::StatusCode::MISDIRECTED_REQUEST => HttpStatusCodeErrors::MISDIRECTED_REQUEST,
155            http::StatusCode::UNPROCESSABLE_ENTITY => HttpStatusCodeErrors::UNPROCESSABLE_ENTITY,
156            http::StatusCode::LOCKED => HttpStatusCodeErrors::LOCKED,
157            http::StatusCode::FAILED_DEPENDENCY => HttpStatusCodeErrors::FAILED_DEPENDENCY,
158            http::StatusCode::UPGRADE_REQUIRED => HttpStatusCodeErrors::UPGRADE_REQUIRED,
159            http::StatusCode::PRECONDITION_REQUIRED => HttpStatusCodeErrors::PRECONDITION_REQUIRED,
160            http::StatusCode::TOO_MANY_REQUESTS => HttpStatusCodeErrors::TOO_MANY_REQUESTS,
161            http::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE => HttpStatusCodeErrors::REQUEST_HEADER_FIELDS_TOO_LARGE,
162            http::StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS => HttpStatusCodeErrors::UNAVAILABLE_FOR_LEGAL_REASONS,
163            http::StatusCode::INTERNAL_SERVER_ERROR => HttpStatusCodeErrors::INTERNAL_SERVER_ERROR,
164            http::StatusCode::NOT_IMPLEMENTED => HttpStatusCodeErrors::NOT_IMPLEMENTED,
165            http::StatusCode::BAD_GATEWAY => HttpStatusCodeErrors::BAD_GATEWAY,
166            http::StatusCode::SERVICE_UNAVAILABLE => HttpStatusCodeErrors::SERVICE_UNAVAILABLE,
167            http::StatusCode::GATEWAY_TIMEOUT => HttpStatusCodeErrors::GATEWAY_TIMEOUT,
168            http::StatusCode::HTTP_VERSION_NOT_SUPPORTED => HttpStatusCodeErrors::HTTP_VERSION_NOT_SUPPORTED,
169            http::StatusCode::VARIANT_ALSO_NEGOTIATES => HttpStatusCodeErrors::VARIANT_ALSO_NEGOTIATES,
170            http::StatusCode::INSUFFICIENT_STORAGE => HttpStatusCodeErrors::INSUFFICIENT_STORAGE,
171            http::StatusCode::LOOP_DETECTED => HttpStatusCodeErrors::LOOP_DETECTED,
172            http::StatusCode::NOT_EXTENDED => HttpStatusCodeErrors::NOT_EXTENDED,
173            http::StatusCode::NETWORK_AUTHENTICATION_REQUIRED => HttpStatusCodeErrors::NETWORK_AUTHENTICATION_REQUIRED,
174            _ => panic!("{} is not an error!", status),
175        }
176    }
177}