lightcone_sdk/api/
error.rs1use std::fmt;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum ApiError {
9 #[error("HTTP error: {0}")]
11 Http(#[from] reqwest::Error),
12
13 #[error("Not found: {0}")]
15 NotFound(ErrorResponse),
16
17 #[error("Bad request: {0}")]
19 BadRequest(ErrorResponse),
20
21 #[error("Permission denied: {0}")]
23 Forbidden(ErrorResponse),
24
25 #[error("Rate limited: {0}")]
27 RateLimited(ErrorResponse),
28
29 #[error("Unauthorized: {0}")]
31 Unauthorized(ErrorResponse),
32
33 #[error("Conflict: {0}")]
35 Conflict(ErrorResponse),
36
37 #[error("Server error: {0}")]
39 ServerError(ErrorResponse),
40
41 #[error("Deserialization error: {0}")]
43 Deserialize(String),
44
45 #[error("Invalid parameter: {0}")]
47 InvalidParameter(String),
48
49 #[error("Unexpected status {0}: {1}")]
51 UnexpectedStatus(u16, ErrorResponse),
52}
53
54impl ApiError {
55 pub fn error_response(&self) -> Option<&ErrorResponse> {
57 match self {
58 ApiError::NotFound(resp) => Some(resp),
59 ApiError::BadRequest(resp) => Some(resp),
60 ApiError::Forbidden(resp) => Some(resp),
61 ApiError::RateLimited(resp) => Some(resp),
62 ApiError::Unauthorized(resp) => Some(resp),
63 ApiError::Conflict(resp) => Some(resp),
64 ApiError::ServerError(resp) => Some(resp),
65 ApiError::UnexpectedStatus(_, resp) => Some(resp),
66 _ => None,
67 }
68 }
69
70 pub fn status_code(&self) -> Option<u16> {
72 match self {
73 ApiError::NotFound(_) => Some(404),
74 ApiError::BadRequest(_) => Some(400),
75 ApiError::Forbidden(_) => Some(403),
76 ApiError::RateLimited(_) => Some(429),
77 ApiError::Unauthorized(_) => Some(401),
78 ApiError::Conflict(_) => Some(409),
79 ApiError::ServerError(_) => Some(500),
80 ApiError::UnexpectedStatus(code, _) => Some(*code),
81 _ => None,
82 }
83 }
84}
85
86pub type ApiResult<T> = Result<T, ApiError>;
88
89#[derive(Debug, Clone, serde::Deserialize)]
91pub struct ErrorResponse {
92 #[serde(default)]
94 pub status: Option<String>,
95 #[serde(alias = "error")]
97 pub message: Option<String>,
98 #[serde(default)]
100 pub details: Option<String>,
101}
102
103impl ErrorResponse {
104 pub fn from_text(text: String) -> Self {
108 Self {
109 status: None,
110 message: Some(text),
111 details: None,
112 }
113 }
114
115 #[deprecated(note = "Use Display formatting instead")]
117 pub fn get_message(&self) -> String {
118 self.message
119 .clone()
120 .or_else(|| self.details.clone())
121 .unwrap_or_else(|| "Unknown error".to_string())
122 }
123}
124
125impl fmt::Display for ErrorResponse {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match (&self.message, &self.details) {
128 (Some(msg), Some(details)) => write!(f, "{}: {}", msg, details),
129 (Some(msg), None) => write!(f, "{}", msg),
130 (None, Some(details)) => write!(f, "{}", details),
131 (None, None) => write!(f, "Unknown error"),
132 }
133 }
134}