use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ApiError {
pub status: u16,
pub kind: ErrorKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resource: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub context: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub suggestion: Option<String>,
}
impl std::fmt::Display for ApiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.status, self.kind.as_str())?;
if let Some(ref msg) = self.message {
write!(f, ": {msg}")?;
}
Ok(())
}
}
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize
)]
#[serde(rename_all = "snake_case")]
pub enum ErrorKind {
MissingPathParam,
BadRequest,
MissingAuthToken,
MalformedAuthToken,
Unauthorized,
Forbidden,
NotFound,
Conflict,
TooManyRequests,
#[default]
InternalServerError,
NotImplemented,
}
impl ErrorKind {
pub fn as_str(&self) -> &'static str {
match self {
Self::MissingPathParam => "missing_path_param",
Self::BadRequest => "bad_request",
Self::MissingAuthToken => "missing_auth_token",
Self::MalformedAuthToken => "malformed_auth_token",
Self::Unauthorized => "unauthorized",
Self::Forbidden => "forbidden",
Self::NotFound => "not_found",
Self::Conflict => "conflict",
Self::TooManyRequests => "too_many_requests",
Self::InternalServerError => "internal_server_error",
Self::NotImplemented => "not_implemented",
}
}
}