Skip to main content

ares_http/
error.rs

1//! HTTP mapping for [`ares_types::AppError`].
2//!
3//! `IntoResponse` cannot be implemented on the foreign `AppError` type here
4//! (orphan rule). Handlers return [`HttpError`], which converts from `AppError`.
5
6use axum::http::StatusCode;
7use axum::response::{IntoResponse, Response};
8use axum::Json;
9
10/// HTTP adapter around [`ares_types::AppError`].
11#[derive(Debug)]
12pub struct HttpError(pub ares_types::AppError);
13
14impl From<ares_types::AppError> for HttpError {
15    fn from(value: ares_types::AppError) -> Self {
16        Self(value)
17    }
18}
19
20impl From<std::io::Error> for HttpError {
21    fn from(err: std::io::Error) -> Self {
22        Self(err.into())
23    }
24}
25
26impl From<serde_json::Error> for HttpError {
27    fn from(err: serde_json::Error) -> Self {
28        Self(err.into())
29    }
30}
31
32impl std::fmt::Display for HttpError {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        self.0.fmt(f)
35    }
36}
37
38impl std::error::Error for HttpError {
39    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40        Some(&self.0)
41    }
42}
43
44impl IntoResponse for HttpError {
45    fn into_response(self) -> Response {
46        app_error_into_response(self.0)
47    }
48}
49
50/// Map [`ares_types::AppError`] to an Axum response using [`ares_types::AppError::status_code`].
51pub fn app_error_into_response(err: ares_types::AppError) -> Response {
52    if matches!(
53        err,
54        ares_types::AppError::Database(_)
55            | ares_types::AppError::LLM(_)
56            | ares_types::AppError::Configuration(_)
57            | ares_types::AppError::Internal(_)
58    ) {
59        tracing::error!(error = %err, code = ?err.code(), "Internal error occurred");
60    }
61
62    let status = StatusCode::from_u16(err.status_code())
63        .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
64    let message = err.to_string();
65    let body = serde_json::json!({
66        "error": message,
67        "code": err.code()
68    });
69    (status, Json(body)).into_response()
70}