1use facet::Facet;
2use serde::{Deserialize, Serialize};
3use thiserror::Error as ThisError;
4
5#[derive(Facet, Serialize, Deserialize, PartialEq, Eq, Clone, ThisError, Debug)]
6#[repr(C)]
7pub enum HttpError {
8 #[error("URL parse error: {0}")]
11 Url(String),
12 #[error("IO error: {0}")]
13 Io(String),
14 #[error("Timeout")]
15 Timeout,
16
17 #[error("HTTP error {code}: {message}")]
19 #[serde(skip)]
20 #[facet(skip)]
21 Http {
22 #[facet(opaque)]
23 code: http_types::StatusCode,
24 message: String,
25 body: Option<Vec<u8>>,
26 },
27 #[error("JSON serialization error: {0}")]
28 #[serde(skip)]
29 #[facet(skip)]
30 Json(String),
31}
32
33impl From<http_types::Error> for HttpError {
34 fn from(e: http_types::Error) -> Self {
35 HttpError::Http {
36 code: e.status(),
37 message: e.to_string(),
38 body: None,
39 }
40 }
41}
42
43impl From<serde_json::Error> for HttpError {
44 fn from(e: serde_json::Error) -> Self {
45 HttpError::Json(e.to_string())
46 }
47}
48
49impl From<url::ParseError> for HttpError {
50 fn from(e: url::ParseError) -> Self {
51 HttpError::Url(e.to_string())
52 }
53}
54
55impl From<serde_qs::Error> for HttpError {
56 fn from(e: serde_qs::Error) -> Self {
57 HttpError::Json(e.to_string())
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn test_error_display() {
67 let error = HttpError::Http {
68 code: http_types::StatusCode::BadRequest,
69 message: "Bad Request".to_string(),
70 body: None,
71 };
72 assert_eq!(error.to_string(), "HTTP error 400: Bad Request");
73 }
74}