use axum::{ http::StatusCode, response::{IntoResponse, Response}, Json, }; use serde_json::json; #[derive(Debug)] pub enum AppError { Unauthorized, NotFound, BadRequest(String), /// The caller must wait this many seconds before trying again. TooManyRequests(i64), Internal(anyhow::Error), } pub type AppResult = Result; impl IntoResponse for AppError { fn into_response(self) -> Response { let (status, message) = match self { AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "unauthorized".to_string()), AppError::NotFound => (StatusCode::NOT_FOUND, "not found".to_string()), AppError::BadRequest(m) => (StatusCode::BAD_REQUEST, m), AppError::TooManyRequests(wait) => ( StatusCode::TOO_MANY_REQUESTS, format!("too many attempts — wait {wait}s"), ), AppError::Internal(e) => { tracing::error!("internal error: {e:#}"); ( StatusCode::INTERNAL_SERVER_ERROR, "internal error".to_string(), ) } }; (status, Json(json!({ "error": message }))).into_response() } } impl From for AppError where E: Into, { fn from(err: E) -> Self { AppError::Internal(err.into()) } }