Skip to main content

crux_http/
error.rs

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    // potentially external, have representation in shells
9    // Note: must come first to preserve discriminant order on both sides of FFI
10    #[error("URL parse error: {0}")]
11    Url(String),
12    #[error("IO error: {0}")]
13    Io(String),
14    #[error("Timeout")]
15    Timeout,
16
17    // internal only, not generated or serialized
18    #[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}