use axum::{ http::StatusCode, response::{IntoResponse, Response}, Json, }; use serde::Serialize; use thiserror::Error; #[derive(Debug, Error)] pub enum AppError { #[error("{0}")] BadRequest(String), #[error("{0}")] NotFound(String), #[error("{0}")] Conflict(String), #[error("{0}")] ServiceUnavailable(String), #[error("{0}")] Internal(String), } #[derive(Debug, Serialize)] struct ErrorResponse { code: &'static str, message: String, } impl AppError { pub fn bad_request(message: impl Into) -> Self { Self::BadRequest(message.into()) } pub fn not_found(message: impl Into) -> Self { Self::NotFound(message.into()) } fn status_code(&self) -> StatusCode { match self { Self::BadRequest(_) => StatusCode::BAD_REQUEST, Self::NotFound(_) => StatusCode::NOT_FOUND, Self::Conflict(_) => StatusCode::CONFLICT, Self::ServiceUnavailable(_) => StatusCode::SERVICE_UNAVAILABLE, Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, } } fn code(&self) -> &'static str { match self { Self::BadRequest(_) => "bad_request", Self::NotFound(_) => "not_found", Self::Conflict(_) => "conflict", Self::ServiceUnavailable(_) => "service_unavailable", Self::Internal(_) => "internal_error", } } } impl IntoResponse for AppError { fn into_response(self) -> Response { let status = self.status_code(); let body = Json(ErrorResponse { code: self.code(), message: self.to_string(), }); (status, body).into_response() } }