Skip to main content

rvf_server/
error.rs

1//! Error types and HTTP error responses for the RVF server.
2
3use axum::http::StatusCode;
4use axum::response::{IntoResponse, Response};
5use serde::Serialize;
6
7/// Application-level error type.
8#[derive(Debug)]
9pub enum ServerError {
10    /// The store returned an error.
11    Store(rvf_types::RvfError),
12    /// A request body could not be deserialized.
13    BadRequest(String),
14    /// The store is not initialized yet.
15    NotReady,
16}
17
18/// JSON body returned on error.
19#[derive(Serialize)]
20struct ErrorBody {
21    error: String,
22    code: u16,
23}
24
25impl IntoResponse for ServerError {
26    fn into_response(self) -> Response {
27        let (status, message, code) = match &self {
28            ServerError::Store(e) => {
29                let code = error_code(e);
30                let status = status_for_error(e);
31                (status, format!("{e:?}"), code)
32            }
33            ServerError::BadRequest(msg) => {
34                (StatusCode::BAD_REQUEST, msg.clone(), 400)
35            }
36            ServerError::NotReady => {
37                (StatusCode::SERVICE_UNAVAILABLE, "Store not ready".into(), 503)
38            }
39        };
40
41        let body = ErrorBody {
42            error: message,
43            code,
44        };
45
46        (status, axum::Json(body)).into_response()
47    }
48}
49
50fn error_code(e: &rvf_types::RvfError) -> u16 {
51    match e {
52        rvf_types::RvfError::Code(c) => *c as u16,
53        _ => 500,
54    }
55}
56
57fn status_for_error(e: &rvf_types::RvfError) -> StatusCode {
58    match e {
59        rvf_types::RvfError::Code(c) => match c {
60            rvf_types::ErrorCode::DimensionMismatch => StatusCode::BAD_REQUEST,
61            rvf_types::ErrorCode::ReadOnly => StatusCode::FORBIDDEN,
62            rvf_types::ErrorCode::LockHeld => StatusCode::CONFLICT,
63            rvf_types::ErrorCode::ManifestNotFound => StatusCode::NOT_FOUND,
64            _ => StatusCode::INTERNAL_SERVER_ERROR,
65        },
66        _ => StatusCode::INTERNAL_SERVER_ERROR,
67    }
68}
69
70impl From<rvf_types::RvfError> for ServerError {
71    fn from(e: rvf_types::RvfError) -> Self {
72        ServerError::Store(e)
73    }
74}