Skip to main content

ling_http/
error.rs

1use axum::{
2    http::StatusCode,
3    response::{IntoResponse, Response},
4    Json,
5};
6use serde_json::json;
7
8/// Uniform error type for ling-http handlers. Converts to a JSON body of the
9/// shape `{"error": "..."}` with a matching HTTP status code, so every API
10/// built on this framework returns errors in one consistent shape.
11#[derive(Debug, thiserror::Error)]
12pub enum HttpError {
13    #[error("not found")]
14    NotFound,
15
16    #[error("bad request: {0}")]
17    BadRequest(String),
18
19    #[error("unauthorized")]
20    Unauthorized,
21
22    #[error("forbidden")]
23    Forbidden,
24
25    #[error("conflict: {0}")]
26    Conflict(String),
27
28    #[error("database error: {0}")]
29    Database(#[from] rusqlite::Error),
30
31    #[error("database pool error: {0}")]
32    Pool(#[from] r2d2::Error),
33
34    #[error("internal error: {0}")]
35    Internal(#[from] anyhow::Error),
36}
37
38impl HttpError {
39    fn status(&self) -> StatusCode {
40        match self {
41            HttpError::NotFound => StatusCode::NOT_FOUND,
42            HttpError::BadRequest(_) => StatusCode::BAD_REQUEST,
43            HttpError::Unauthorized => StatusCode::UNAUTHORIZED,
44            HttpError::Forbidden => StatusCode::FORBIDDEN,
45            HttpError::Conflict(_) => StatusCode::CONFLICT,
46            HttpError::Database(rusqlite::Error::QueryReturnedNoRows) => StatusCode::NOT_FOUND,
47            HttpError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
48            HttpError::Pool(_) => StatusCode::INTERNAL_SERVER_ERROR,
49            HttpError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
50        }
51    }
52}
53
54impl IntoResponse for HttpError {
55    fn into_response(self) -> Response {
56        let status = self.status();
57        if status == StatusCode::INTERNAL_SERVER_ERROR {
58            tracing::error!(error = %self, "internal error");
59        }
60        (status, Json(json!({ "error": self.to_string() }))).into_response()
61    }
62}
63
64pub type Result<T> = std::result::Result<T, HttpError>;