Files
corrosion-admin-panel/backend/src/models/error.rs
Vantz Stockwell 5c11050eca scaffold: Backend core — Cargo.toml, main.rs, config, models, panel adapter
Axum server entry point, AppConfig, AppState, ApiError, all model
structs (auth, license, server, wipe), and the PanelAdapter trait
that abstracts AMP/Pterodactyl/companion connections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:41:58 -05:00

112 lines
3.2 KiB
Rust

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::Serialize;
/// Unified API error type
#[derive(Debug, thiserror::Error)]
pub enum ApiError {
#[error("Not found: {0}")]
NotFound(String),
#[error("Bad request: {0}")]
BadRequest(String),
#[error("Unauthorized")]
Unauthorized,
#[error("Forbidden")]
Forbidden,
#[error("Conflict: {0}")]
Conflict(String),
#[error("License invalid or expired")]
LicenseInvalid,
#[error("Module not enabled: {0}")]
ModuleNotEnabled(String),
#[error("Rate limited")]
RateLimited,
#[error("Internal error: {0}")]
Internal(String),
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
}
#[derive(Serialize)]
struct ErrorResponse {
error: String,
message: String,
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let (status, error_type, message) = match &self {
ApiError::NotFound(msg) => (StatusCode::NOT_FOUND, "not_found", msg.clone()),
ApiError::BadRequest(msg) => (StatusCode::BAD_REQUEST, "bad_request", msg.clone()),
ApiError::Unauthorized => {
(StatusCode::UNAUTHORIZED, "unauthorized", "Unauthorized".to_string())
}
ApiError::Forbidden => {
(StatusCode::FORBIDDEN, "forbidden", "Forbidden".to_string())
}
ApiError::Conflict(msg) => (StatusCode::CONFLICT, "conflict", msg.clone()),
ApiError::LicenseInvalid => (
StatusCode::PAYMENT_REQUIRED,
"license_invalid",
"License invalid or expired".to_string(),
),
ApiError::ModuleNotEnabled(module) => (
StatusCode::PAYMENT_REQUIRED,
"module_not_enabled",
format!("Module not enabled: {module}"),
),
ApiError::RateLimited => (
StatusCode::TOO_MANY_REQUESTS,
"rate_limited",
"Too many requests".to_string(),
),
ApiError::Internal(msg) => {
tracing::error!("Internal error: {msg}");
(
StatusCode::INTERNAL_SERVER_ERROR,
"internal_error",
"Internal server error".to_string(),
)
}
ApiError::Database(e) => {
tracing::error!("Database error: {e}");
(
StatusCode::INTERNAL_SERVER_ERROR,
"internal_error",
"Internal server error".to_string(),
)
}
ApiError::Anyhow(e) => {
tracing::error!("Unexpected error: {e}");
(
StatusCode::INTERNAL_SERVER_ERROR,
"internal_error",
"Internal server error".to_string(),
)
}
};
let body = ErrorResponse {
error: error_type.to_string(),
message,
};
(status, axum::Json(body)).into_response()
}
}
/// Result alias for API handlers
pub type ApiResult<T> = Result<T, ApiError>;