lora_server/app/
errors.rs1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4 Json,
5};
6use lora_database::{LoraError, LoraErrorCode};
7use serde::Serialize;
8
9#[derive(Debug, Serialize)]
22pub struct ErrorResponse {
23 pub error: ErrorBody,
24}
25
26#[derive(Debug, Serialize)]
27pub struct ErrorBody {
28 pub code: &'static str,
29 pub message: String,
30 pub category: &'static str,
31}
32
33impl ErrorResponse {
34 fn from_lora(err: &LoraError) -> Self {
35 Self {
36 error: ErrorBody {
37 code: err.code().as_str(),
38 message: err.message().to_string(),
39 category: err.category().as_str(),
40 },
41 }
42 }
43
44 pub(crate) fn from_parts(code: LoraErrorCode, message: impl Into<String>) -> Self {
47 Self {
48 error: ErrorBody {
49 code: code.as_str(),
50 message: message.into(),
51 category: code.category().as_str(),
52 },
53 }
54 }
55}
56
57fn status_for(err: &LoraError) -> StatusCode {
71 match err.code() {
72 LoraErrorCode::WalPoisoned => StatusCode::SERVICE_UNAVAILABLE,
74 LoraErrorCode::Io
75 | LoraErrorCode::WalCorruption
76 | LoraErrorCode::SnapshotCodec
77 | LoraErrorCode::SnapshotCrypto
78 | LoraErrorCode::Internal => StatusCode::INTERNAL_SERVER_ERROR,
79 LoraErrorCode::Timeout => StatusCode::REQUEST_TIMEOUT,
81 LoraErrorCode::NotFound => StatusCode::NOT_FOUND,
82 LoraErrorCode::InvalidParams | LoraErrorCode::InvalidVector => {
83 StatusCode::UNPROCESSABLE_ENTITY
84 }
85 LoraErrorCode::ConstraintViolation => StatusCode::CONFLICT,
86 LoraErrorCode::Parse
87 | LoraErrorCode::Semantic
88 | LoraErrorCode::ReadOnlyViolation
89 | LoraErrorCode::DatabaseName
90 | LoraErrorCode::Config => StatusCode::BAD_REQUEST,
91 }
92}
93
94pub(crate) fn lora_error_response(err: impl Into<LoraError>) -> Response {
95 let lora = err.into();
96 let status = status_for(&lora);
97 (status, Json(ErrorResponse::from_lora(&lora))).into_response()
98}