53 lines
1.9 KiB
Rust
53 lines
1.9 KiB
Rust
use axum::http::StatusCode;
|
|
use axum::response::{IntoResponse, Response};
|
|
use serde_json::json;
|
|
|
|
pub enum AppError {
|
|
Unauthorized,
|
|
BadRequest(String),
|
|
NotFound(String),
|
|
/// 403 — authenticated but lacks permission (e.g. non-admin calling an
|
|
/// admin-only endpoint).
|
|
Forbidden(String),
|
|
/// 409 — request is valid but conflicts with current state (e.g. an
|
|
/// analysis is already running for this case).
|
|
Conflict(String),
|
|
/// 503 — the feature is unavailable right now (e.g. no LLM configured).
|
|
ServiceUnavailable(String),
|
|
Internal(String),
|
|
/// 302 redirect. Used by web auth to send unauthenticated users to login.
|
|
Redirect(String),
|
|
}
|
|
|
|
impl IntoResponse for AppError {
|
|
fn into_response(self) -> Response {
|
|
if let Self::Redirect(url) = &self {
|
|
return Response::builder()
|
|
.status(StatusCode::FOUND)
|
|
.header(axum::http::header::LOCATION, url)
|
|
.body(axum::body::Body::empty())
|
|
.unwrap();
|
|
}
|
|
|
|
let (status, message) = match &self {
|
|
Self::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".to_owned()),
|
|
Self::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
|
|
Self::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
|
Self::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
|
|
Self::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()),
|
|
Self::ServiceUnavailable(msg) => (StatusCode::SERVICE_UNAVAILABLE, msg.clone()),
|
|
Self::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
|
|
Self::Redirect(_) => unreachable!(),
|
|
};
|
|
|
|
let body = axum::Json(json!({ "error": message }));
|
|
(status, body).into_response()
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for AppError {
|
|
fn from(err: std::io::Error) -> Self {
|
|
Self::Internal(err.to_string())
|
|
}
|
|
}
|