Files
herbapi/herbapi-api/src/error.rs
T
florian.berthold 484979ad53 Initial HerbAPI implementation
Rust/Axum REST API (herbapi-api) with PostgreSQL, S3/Garage, OIDC auth.
Dioxus 0.7 WASM frontend (herbapi-ui) with sidebar layout and botanical reference style.
9 SQL migrations covering families, species, cultivars, suppliers, companions, images, users, API tokens.
2026-03-14 00:02:29 +01:00

63 lines
1.8 KiB
Rust

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde_json::json;
pub type Result<T> = std::result::Result<T, AppError>;
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Not found: {0}")]
NotFound(String),
#[error("Unauthorized: {0}")]
#[allow(dead_code)]
Unauthorized(String),
#[error("Bad request: {0}")]
BadRequest(String),
#[error("Forbidden")]
Forbidden,
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("S3 error: {0}")]
S3(String),
#[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::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg.clone()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
AppError::Forbidden => (StatusCode::FORBIDDEN, "Forbidden".to_string()),
AppError::Database(e) => {
tracing::error!("Database error: {e}");
(
StatusCode::INTERNAL_SERVER_ERROR,
"Database error".to_string(),
)
}
AppError::S3(msg) => {
tracing::error!("S3 error: {msg}");
(StatusCode::INTERNAL_SERVER_ERROR, "Storage error".to_string())
}
AppError::Internal(msg) => {
tracing::error!("Internal error: {msg}");
(
StatusCode::INTERNAL_SERVER_ERROR,
"Internal error".to_string(),
)
}
};
let body = axum::Json(json!({ "error": message }));
(status, body).into_response()
}
}