use axum::{ body::Body, http::{Response, StatusCode}, response::IntoResponse, }; use thiserror::Error; #[derive(Error, Debug)] pub enum HttpError { #[error("db shit itself: {0}")] DbErr(#[from] sea_orm::DbErr), #[error("hashing failed")] Hash, #[error("resource not found")] NotFound, #[error("unauthorized")] Unauthorized, #[error("forbidden")] Forbidden, #[error("conflict")] Conflict, #[error("bad request: {0}")] BadRequest(String), #[error("unprocessable entity: {0}")] Unprocessable(String), #[error("not acceptable: {0}")] NotAcceptable(String), #[error("internal error")] Internal, } impl HttpError { fn status(&self) -> StatusCode { match self { Self::DbErr(_) | Self::Hash | Self::Internal => StatusCode::INTERNAL_SERVER_ERROR, Self::NotFound => StatusCode::NOT_FOUND, Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::Forbidden => StatusCode::FORBIDDEN, Self::Conflict => StatusCode::CONFLICT, Self::BadRequest(_) => StatusCode::BAD_REQUEST, Self::Unprocessable(_) => StatusCode::UNPROCESSABLE_ENTITY, Self::NotAcceptable(_) => StatusCode::NOT_ACCEPTABLE, } } } impl IntoResponse for HttpError { fn into_response(self) -> Response { let status = self.status(); // Only surface a message body for client (4xx) errors; keep an empty // body for 5xx so internal details aren't leaked. let body = if status.is_client_error() { self.to_string() } else { String::new() }; (status, body).into_response() } }