use crate::macros::impl_display_for_serialize;
use reqwest::StatusCode;
use std::fmt::Display;
#[derive(Debug, Clone, thiserror::Error)]
pub struct ValidationError<T>
where
T: Display,
{
pub _type: String,
pub expected: String,
pub actual: T,
}
impl<T> Display for ValidationError<T>
where
T: Display,
{
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(
f,
"Validation error: ({}) {}, actual value: {}",
self._type, self.expected, self.actual,
)
}
}
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error("HTTP request error: {0:?}")]
HttpRequestError(reqwest::Error),
#[error("Reading response text failed: {0:?}")]
ReadResponseTextFailed(reqwest::Error),
#[error("Failed to deserialize response as JSON: {error:?}, {text:?}")]
ResponseDeserializationFailed {
error: serde_json::Error,
text: String,
},
#[error(
"Failed to deserialize error response as JSON: {error:?}, {text:?}"
)]
ErrorResponseDeserializationFailed {
error: serde_json::Error,
text: String,
},
}
#[derive(Debug, Clone, thiserror::Error)]
pub struct ApiError {
pub status: StatusCode,
pub _type: ApiErrorType,
pub response: ApiErrorResponse,
}
impl Display for ApiError {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(
f,
"API error: ({}) {}: {}",
self.status, self._type, self.response,
)
}
}
impl ApiError {
pub(crate) fn new(
status: StatusCode,
response: ApiErrorResponse,
) -> Self {
let _type = ApiErrorType::from(status);
Self {
status,
_type,
response,
}
}
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ApiErrorResponse {
#[serde(rename = "type")]
pub _type: String,
pub error: ApiErrorBody,
}
impl_display_for_serialize!(ApiErrorResponse);
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ApiErrorBody {
#[serde(rename = "type")]
pub _type: String,
pub message: String,
}
impl_display_for_serialize!(ApiErrorBody);
#[derive(Debug, Clone, PartialEq)]
pub enum ApiErrorType {
InvalidRequestError,
AuthenticationError,
PermissionError,
NotFoundError,
RateLimitError,
ApiError,
OverloadedError,
Unknown(StatusCode),
}
impl Display for ApiErrorType {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
match self {
| ApiErrorType::InvalidRequestError => {
write!(f, "invalid_request_error")
},
| ApiErrorType::AuthenticationError => {
write!(f, "authentication_error")
},
| ApiErrorType::PermissionError => {
write!(f, "permission_error")
},
| ApiErrorType::NotFoundError => {
write!(f, "not_found_error")
},
| ApiErrorType::RateLimitError => {
write!(f, "rate_limit_error")
},
| ApiErrorType::ApiError => {
write!(f, "api_error")
},
| ApiErrorType::OverloadedError => {
write!(f, "overloaded_error")
},
| ApiErrorType::Unknown(status) => {
write!(f, "unknown_error({})", status)
},
}
}
}
impl From<StatusCode> for ApiErrorType {
fn from(status: StatusCode) -> Self {
if status == StatusCode::from_u16(529).unwrap() {
return Self::OverloadedError;
}
match status {
| StatusCode::BAD_REQUEST => Self::InvalidRequestError,
| StatusCode::UNAUTHORIZED => Self::AuthenticationError,
| StatusCode::FORBIDDEN => Self::PermissionError,
| StatusCode::NOT_FOUND => Self::NotFoundError,
| StatusCode::TOO_MANY_REQUESTS => Self::RateLimitError,
| StatusCode::INTERNAL_SERVER_ERROR => Self::ApiError,
| unknown => Self::Unknown(unknown),
}
}
}