use crate::{kind::AppError, public::PublicError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PublicErrorCode {
InvalidRequest,
Forbidden,
NotFound,
Conflict,
TemporarilyUnavailable,
InternalError,
RateLimited,
}
impl PublicErrorCode {
#[must_use]
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::InvalidRequest => "invalid_request",
Self::Forbidden => "forbidden",
Self::NotFound => "not_found",
Self::Conflict => "conflict",
Self::TemporarilyUnavailable => "temporarily_unavailable",
Self::InternalError => "internal_error",
Self::RateLimited => "rate_limited",
}
}
}
#[must_use]
pub(crate) fn public_error_code_for(err: &AppError) -> PublicErrorCode {
match err {
AppError::Validation { .. } => PublicErrorCode::InvalidRequest,
AppError::Forbidden { .. } => PublicErrorCode::Forbidden,
AppError::NotFound => PublicErrorCode::NotFound,
AppError::Conflict => PublicErrorCode::Conflict,
AppError::Dependency { .. } => PublicErrorCode::TemporarilyUnavailable,
AppError::Crypto | AppError::Internal => PublicErrorCode::InternalError,
AppError::RateLimit { .. } => PublicErrorCode::RateLimited,
}
}
pub fn into_response_parts(err: &AppError) -> (u16, PublicError) {
let code = public_error_code_for(err).as_str();
match err {
AppError::Validation { .. } => (
400,
PublicError::new(code, "The request contains invalid data.", None),
),
AppError::Forbidden { .. } => (403, PublicError::new(code, "Access denied.", None)),
AppError::NotFound => (
404,
PublicError::new(code, "The requested resource was not found.", None),
),
AppError::Conflict => (
409,
PublicError::new(code, "The request conflicts with the current state.", None),
),
AppError::Dependency { .. } => (
503,
PublicError::new(code, "A required service is temporarily unavailable.", None),
),
AppError::Crypto | AppError::Internal => (
500,
PublicError::new(code, "An internal error occurred.", None),
),
AppError::RateLimit { .. } => (
429,
PublicError::new(code, "Too many requests. Please retry later.", None),
),
}
}
#[must_use]
pub fn retry_after_seconds(err: &AppError) -> Option<u64> {
match err {
AppError::RateLimit {
retry_after_seconds,
} => *retry_after_seconds,
_ => None,
}
}