use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use lmrc_http_common::error::ErrorResponse;
use sea_orm::DbErr;
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Database error: {0}")]
Database(#[from] DbErr),
#[error("Not found: {0}")]
NotFound(String),
#[error("Bad request: {0}")]
BadRequest(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Internal server error: {0}")]
Internal(String),
}
impl AppError {
fn status_code(&self) -> StatusCode {
match self {
AppError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
AppError::NotFound(_) => StatusCode::NOT_FOUND,
AppError::BadRequest(_) => StatusCode::BAD_REQUEST,
AppError::Validation(_) => StatusCode::UNPROCESSABLE_ENTITY,
AppError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_code(&self) -> &str {
match self {
AppError::Database(_) => "DATABASE_ERROR",
AppError::NotFound(_) => "NOT_FOUND",
AppError::BadRequest(_) => "BAD_REQUEST",
AppError::Validation(_) => "VALIDATION_ERROR",
AppError::Internal(_) => "INTERNAL_ERROR",
}
}
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let status = self.status_code();
let message = self.to_string();
let error_code = self.error_code();
tracing::error!(
status = %status.as_u16(),
error_code = %error_code,
message = %message,
"Request error"
);
(
status,
Json(ErrorResponse::new(error_code, message)),
)
.into_response()
}
}
pub type Result<T> = std::result::Result<T, AppError>;