Create utility functions
This commit is contained in:
142
server/src/utils/error.rs
Normal file
142
server/src/utils/error.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Json, Response},
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppError {
|
||||
DatabaseError(String),
|
||||
ValidationError(String),
|
||||
AuthenticationError(String),
|
||||
AuthorizationError(String),
|
||||
NotFoundError(String),
|
||||
ConflictError(String),
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for AppError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AppError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
|
||||
AppError::ValidationError(msg) => write!(f, "Validation error: {}", msg),
|
||||
AppError::AuthenticationError(msg) => write!(f, "Authentication error: {}", msg),
|
||||
AppError::AuthorizationError(msg) => write!(f, "Authorization error: {}", msg),
|
||||
AppError::NotFoundError(msg) => write!(f, "Not found: {}", msg),
|
||||
AppError::ConflictError(msg) => write!(f, "Conflict: {}", msg),
|
||||
AppError::InternalError(msg) => write!(f, "Internal error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AppError {}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, error_message) = match self {
|
||||
AppError::DatabaseError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Database error"),
|
||||
AppError::ValidationError(ref msg) => (StatusCode::BAD_REQUEST, msg.as_str()),
|
||||
AppError::AuthenticationError(ref msg) => (StatusCode::UNAUTHORIZED, msg.as_str()),
|
||||
AppError::AuthorizationError(ref msg) => (StatusCode::FORBIDDEN, msg.as_str()),
|
||||
AppError::NotFoundError(ref msg) => (StatusCode::NOT_FOUND, msg.as_str()),
|
||||
AppError::ConflictError(ref msg) => (StatusCode::CONFLICT, msg.as_str()),
|
||||
AppError::InternalError(_) => {
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Internal server error")
|
||||
}
|
||||
};
|
||||
|
||||
let body = Json(json!({
|
||||
"error": error_message
|
||||
}));
|
||||
|
||||
(status, body).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for AppError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
if let Some(sqlx_err) = err.downcast_ref::<sqlx::Error>() {
|
||||
match sqlx_err {
|
||||
sqlx::Error::RowNotFound => {
|
||||
AppError::NotFoundError("Resource not found".to_string())
|
||||
}
|
||||
sqlx::Error::Database(db_err) => {
|
||||
if db_err.message().contains("UNIQUE constraint failed") {
|
||||
AppError::ConflictError("Resource already exists".to_string())
|
||||
} else {
|
||||
AppError::DatabaseError(db_err.message().to_string())
|
||||
}
|
||||
}
|
||||
_ => AppError::DatabaseError("Database operation failed".to_string()),
|
||||
}
|
||||
} else {
|
||||
AppError::InternalError(err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bcrypt::BcryptError> for AppError {
|
||||
fn from(_: bcrypt::BcryptError) -> Self {
|
||||
AppError::InternalError("Password hashing error".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for AppError {
|
||||
fn from(err: sqlx::Error) -> Self {
|
||||
match err {
|
||||
sqlx::Error::RowNotFound => AppError::NotFoundError("Resource not found".to_string()),
|
||||
sqlx::Error::Database(db_err) => {
|
||||
if db_err.message().contains("UNIQUE constraint failed") {
|
||||
AppError::ConflictError("Resource already exists".to_string())
|
||||
} else {
|
||||
AppError::DatabaseError(db_err.message().to_string())
|
||||
}
|
||||
}
|
||||
_ => AppError::DatabaseError("Database operation failed".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for AppError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
AppError::InternalError(format!("IO error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
pub type AppResult<T> = Result<T, AppError>;
|
||||
|
||||
pub fn validation_error(msg: &str) -> AppError {
|
||||
AppError::ValidationError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn auth_error(msg: &str) -> AppError {
|
||||
AppError::AuthenticationError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn forbidden_error(msg: &str) -> AppError {
|
||||
AppError::AuthorizationError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn not_found_error(msg: &str) -> AppError {
|
||||
AppError::NotFoundError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn conflict_error(msg: &str) -> AppError {
|
||||
AppError::ConflictError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn internal_error(msg: &str) -> AppError {
|
||||
AppError::InternalError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn success_response<T>(data: T) -> Json<T>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
Json(data)
|
||||
}
|
||||
|
||||
pub fn success_message(msg: &str) -> Json<serde_json::Value> {
|
||||
Json(json!({ "message": msg }))
|
||||
}
|
Reference in New Issue
Block a user