Files
dota-random-web/src/error_handlers.rs
T
kwiialyssa edb4cd8613
CI/CD / Build (push) Successful in 5m59s
CI/CD / Frontend Build (push) Successful in 1m27s
CI/CD / Unit Tests (push) Failing after 1m12s
CI/CD / Docker (push) Skipped
CI/CD / Frontend Docker (push) Failing after 3m29s
feat(DRW-001) initial commit!
2026-09-13 20:37:48 +03:00

80 lines
2.3 KiB
Rust

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde::Serialize;
#[derive(Serialize)]
struct ErrorBody {
error: String,
}
#[derive(Debug)]
pub enum AppError {
Internal,
NotFound,
BadRequest(String),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
AppError::Internal => (StatusCode::INTERNAL_SERVER_ERROR, "internal server error".to_string()),
AppError::NotFound => (StatusCode::NOT_FOUND, "not found".to_string()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
};
(status, Json(ErrorBody { error: message })).into_response()
}
}
impl From<sqlx::Error> for AppError {
fn from(e: sqlx::Error) -> Self {
tracing::error!("{e}");
AppError::Internal
}
}
#[cfg(test)]
mod tests {
use super::*;
async fn body_json(error: AppError) -> serde_json::Value {
let response = error.into_response();
let bytes = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
serde_json::from_slice(&bytes).unwrap()
}
#[tokio::test]
async fn internal_maps_to_500_with_error_body() {
let response = AppError::Internal.into_response();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
let body = body_json(AppError::Internal).await;
assert_eq!(body["error"], "internal server error");
}
#[tokio::test]
async fn not_found_maps_to_404_with_error_body() {
let response = AppError::NotFound.into_response();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
let body = body_json(AppError::NotFound).await;
assert_eq!(body["error"], "not found");
}
#[tokio::test]
async fn bad_request_maps_to_400_and_carries_its_message() {
let response = AppError::BadRequest("nope".to_string()).into_response();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = body_json(AppError::BadRequest("nope".to_string())).await;
assert_eq!(body["error"], "nope");
}
#[tokio::test]
async fn sqlx_errors_map_to_internal() {
let sqlx_err = sqlx::Error::RowNotFound;
let app_err: AppError = sqlx_err.into();
assert!(matches!(app_err, AppError::Internal));
}
}