use axum::http::StatusCode;
use axum::response::{IntoResponse, Json};
use madhyamas_core::error::AppError;
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct ErrorBody {
pub error: String,
}
#[derive(Debug)]
pub struct ApiError {
pub status: StatusCode,
pub message: String,
}
impl ApiError {
pub fn new(status: StatusCode, message: impl Into<String>) -> Self {
Self {
status,
message: message.into(),
}
}
pub fn bad_request(msg: impl Into<String>) -> Self {
Self::new(StatusCode::BAD_REQUEST, msg)
}
pub fn not_found(msg: impl Into<String>) -> Self {
Self::new(StatusCode::NOT_FOUND, msg)
}
pub fn internal(msg: impl Into<String>) -> Self {
Self::new(StatusCode::INTERNAL_SERVER_ERROR, msg)
}
pub fn service_unavailable(msg: impl Into<String>) -> Self {
Self::new(StatusCode::SERVICE_UNAVAILABLE, msg)
}
}
impl IntoResponse for ApiError {
fn into_response(self) -> axum::response::Response {
(
self.status,
Json(ErrorBody {
error: self.message,
}),
)
.into_response()
}
}
impl From<serde_json::Error> for ApiError {
fn from(e: serde_json::Error) -> Self {
Self::bad_request(format!("JSON error: {}", e))
}
}
impl From<Box<dyn AppError>> for ApiError {
fn from(err: Box<dyn AppError>) -> Self {
let code = err.error_code();
let status = status_for_code(code);
let message = err.to_string();
Self::new(status, message)
}
}
impl ApiError {
pub fn from_app_error<E: AppError>(err: E) -> Self {
let code = err.error_code();
let status = status_for_code(code);
let message = err.to_string();
Self::new(status, message)
}
}
fn status_for_code(code: &str) -> StatusCode {
if let Some(rest) = code.strip_prefix("ENTERPRISE_") {
match rest {
"AUTH_FAILED" | "TOKEN_EXPIRED" | "JWT_ERROR" => StatusCode::UNAUTHORIZED,
"PERMISSION_DENIED" => StatusCode::FORBIDDEN,
"USER_NOT_FOUND" | "ROLE_NOT_FOUND" => StatusCode::NOT_FOUND,
"AUDIT_ERROR" => StatusCode::INTERNAL_SERVER_ERROR,
"INVALID_CONFIG" => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
} else if let Some(rest) = code.strip_prefix("MCP_") {
match rest {
"INVALID_PARAMS" | "PARSE" => StatusCode::BAD_REQUEST,
"NOT_FOUND" => StatusCode::NOT_FOUND,
"HTTP" | "JSON_RPC" => StatusCode::SERVICE_UNAVAILABLE,
"TOOL_EXECUTION" => StatusCode::INTERNAL_SERVER_ERROR,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
} else {
match code {
"CORE_CONFIG" | "CORE_SERIALIZATION" => StatusCode::BAD_REQUEST,
"CORE_DATABASE" => StatusCode::SERVICE_UNAVAILABLE,
_ => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
pub type ApiResult<T> = Result<T, ApiError>;