use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use crate::models::ErrorResponse; #[derive(Debug, thiserror::Error)] pub enum AppError { #[error("Not found: {0}")] NotFound(String), #[error("Bad request: {0}")] BadRequest(String), #[error("Asset is corrupted: {0}")] Corrupted(String), #[error("Database error: {0}")] Database(#[from] rusqlite::Error), #[error("IO error: {0}")] Io(#[from] std::io::Error), #[error("Internal error: {0}")] Internal(String), } impl IntoResponse for AppError { fn into_response(self) -> Response { let (status, message) = match &self { AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()), AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()), AppError::Corrupted(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()), AppError::Database(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()), AppError::Io(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()), AppError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()), }; tracing::error!(%status, error = %message, "request error"); let body = serde_json::to_string(&ErrorResponse::new(message)).unwrap_or_default(); (status, [(axum::http::header::CONTENT_TYPE, "application/json")], body).into_response() } }