use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use serde_json::json; use thiserror::Error; #[derive(Debug, Error)] pub enum ApiError { #[error("Database error: {0}")] Database(#[from] sea_orm::DbErr), #[error("Validation error: {0}")] Validation(String), #[error("Not found: {0}")] NotFound(String), #[error("Bad request: {0}")] BadRequest(String), #[error("Internal server error: {0}")] Internal(String), #[error("Unauthorized: {0}")] Unauthorized(String), #[error("Forbidden: {0}")] Forbidden(String), } impl IntoResponse for ApiError { fn into_response(self) -> Response { let (status, error_message) = match self { ApiError::Database(err) => ( StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", err), ), ApiError::Validation(msg) => (StatusCode::BAD_REQUEST, msg), ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, msg), ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg), ApiError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), ApiError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg), ApiError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg), }; let body = json!({ "error": { "code": status.as_u16(), "message": error_message } }); (status, axum::Json(body)).into_response() } } pub type ApiResult = Result; impl From for ApiError { fn from(err: validator::ValidationErrors) -> Self { let errors: Vec = err .field_errors() .iter() .map(|(field, errors)| { let error_msgs: Vec = errors .iter() .map(|error| { if let Some(msg) = &error.message { msg.to_string() } else { format!("Validation failed for field: {}", field) } }) .collect(); error_msgs.join(", ") }) .collect(); ApiError::Validation(errors.join("; ")) } }