error.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //! HTTP error types
  2. use thiserror::Error;
  3. /// HTTP Response type - generic over the body type R and error type E
  4. /// This is the primary return type for all HTTP operations
  5. pub type Response<R, E = HttpError> = Result<R, E>;
  6. /// HTTP errors that can occur during requests
  7. #[derive(Debug, Error)]
  8. pub enum HttpError {
  9. /// HTTP error with status code
  10. #[error("HTTP error ({status}): {message}")]
  11. Status {
  12. /// HTTP status code
  13. status: u16,
  14. /// Error message
  15. message: String,
  16. },
  17. /// Connection error
  18. #[error("Connection error: {0}")]
  19. Connection(String),
  20. /// Request timeout
  21. #[error("Request timeout")]
  22. Timeout,
  23. /// Serialization error
  24. #[error("Serialization error: {0}")]
  25. Serialization(String),
  26. /// Proxy error
  27. #[error("Proxy error: {0}")]
  28. Proxy(String),
  29. /// Client build error
  30. #[error("Client build error: {0}")]
  31. Build(String),
  32. /// Other error
  33. #[error("{0}")]
  34. Other(String),
  35. }
  36. #[cfg(not(target_arch = "wasm32"))]
  37. impl From<reqwest::Error> for HttpError {
  38. fn from(err: reqwest::Error) -> Self {
  39. if err.is_timeout() {
  40. HttpError::Timeout
  41. } else if err.is_builder() {
  42. HttpError::Build(err.to_string())
  43. } else if let Some(status) = err.status() {
  44. HttpError::Status {
  45. status: status.as_u16(),
  46. message: err.to_string(),
  47. }
  48. } else {
  49. if err.is_connect() {
  50. return HttpError::Connection(err.to_string());
  51. }
  52. HttpError::Other(err.to_string())
  53. }
  54. }
  55. }
  56. impl From<serde_json::Error> for HttpError {
  57. fn from(err: serde_json::Error) -> Self {
  58. HttpError::Serialization(err.to_string())
  59. }
  60. }
  61. #[cfg(test)]
  62. mod tests {
  63. use super::*;
  64. #[test]
  65. fn test_http_error_status_display() {
  66. let error = HttpError::Status {
  67. status: 404,
  68. message: "Not Found".to_string(),
  69. };
  70. assert_eq!(format!("{}", error), "HTTP error (404): Not Found");
  71. }
  72. #[test]
  73. fn test_http_error_connection_display() {
  74. let error = HttpError::Connection("connection refused".to_string());
  75. assert_eq!(format!("{}", error), "Connection error: connection refused");
  76. }
  77. #[test]
  78. fn test_http_error_timeout_display() {
  79. let error = HttpError::Timeout;
  80. assert_eq!(format!("{}", error), "Request timeout");
  81. }
  82. #[test]
  83. fn test_http_error_serialization_display() {
  84. let error = HttpError::Serialization("invalid JSON".to_string());
  85. assert_eq!(format!("{}", error), "Serialization error: invalid JSON");
  86. }
  87. #[test]
  88. fn test_http_error_proxy_display() {
  89. let error = HttpError::Proxy("proxy unreachable".to_string());
  90. assert_eq!(format!("{}", error), "Proxy error: proxy unreachable");
  91. }
  92. #[test]
  93. fn test_http_error_build_display() {
  94. let error = HttpError::Build("invalid config".to_string());
  95. assert_eq!(format!("{}", error), "Client build error: invalid config");
  96. }
  97. #[test]
  98. fn test_http_error_other_display() {
  99. let error = HttpError::Other("unknown error".to_string());
  100. assert_eq!(format!("{}", error), "unknown error");
  101. }
  102. #[test]
  103. fn test_from_serde_json_error() {
  104. let result: Result<String, _> = serde_json::from_str("not valid json");
  105. let json_error = result.expect_err("Invalid JSON should produce an error");
  106. let http_error: HttpError = json_error.into();
  107. match http_error {
  108. HttpError::Serialization(msg) => {
  109. assert!(
  110. msg.contains("expected"),
  111. "Error message should describe JSON error"
  112. );
  113. }
  114. _ => panic!("Expected HttpError::Serialization"),
  115. }
  116. }
  117. #[test]
  118. fn test_response_type_is_result() {
  119. let success: Response<i32> = Ok(42);
  120. assert!(success.is_ok());
  121. assert!(matches!(success, Ok(42)));
  122. let error: Response<i32> = Err(HttpError::Timeout);
  123. assert!(error.is_err());
  124. assert!(matches!(error, Err(HttpError::Timeout)));
  125. }
  126. }