use derive_more::{Display, Error};
use foundation_errstacks::ErrorTrace;
use serde::Serialize;
pub type AppResult<T> = Result<T, ErrorTrace<AppError>>;
#[derive(Debug, Display, Error)]
pub enum AppError {
#[display("bad request: {_0}")]
BadRequest(#[error(not(source))] String),
#[display("unauthorized")]
Unauthorized,
#[display("forbidden")]
Forbidden,
#[display("not found: {_0}")]
NotFound(#[error(not(source))] String),
#[display("conflict: {_0}")]
Conflict(#[error(not(source))] String),
#[display("too many requests")]
RateLimited,
#[display("internal: {_0}")]
Internal(#[error(not(source))] String),
}
impl From<AppError> for ErrorTrace<AppError> {
fn from(err: AppError) -> Self {
ErrorTrace::new(err)
}
}
impl AppError {
#[must_use]
pub fn status(&self) -> u16 {
match self {
Self::BadRequest(_) => 400,
Self::Unauthorized => 401,
Self::Forbidden => 403,
Self::NotFound(_) => 404,
Self::Conflict(_) => 409,
Self::RateLimited => 429,
Self::Internal(_) => 500,
}
}
#[must_use]
pub fn to_json(&self) -> serde_json::Value {
let (error, description) = match self {
Self::BadRequest(msg) => ("invalid_request", msg.clone()),
Self::Unauthorized => ("invalid_token", "The access token is invalid".into()),
Self::Forbidden => ("access_denied", "You do not have permission".into()),
Self::NotFound(msg) => ("not_found", msg.clone()),
Self::Conflict(msg) => ("conflict", msg.clone()),
Self::RateLimited => ("rate_limited", "Too many requests".into()),
Self::Internal(msg) => ("internal_error", msg.clone()),
};
serde_json::json!({
"error": error,
"error_description": description,
"ErrorModel": {
"Message": description,
"Object": "error"
}
})
}
}
#[derive(Debug, Serialize)]
pub struct ValidationError {
pub message: String,
pub object: String,
}
impl ValidationError {
#[must_use]
pub fn new(message: impl Into<String>, object: impl Into<String>) -> Self {
Self {
message: message.into(),
object: object.into(),
}
}
}