Skip to main content

omnia_sdk/api/
into_http.rs

1use axum::response::{IntoResponse, Response};
2use http::header::CONTENT_TYPE;
3use http::{HeaderValue, StatusCode};
4
5use crate::api::Body;
6use crate::api::reply::Reply;
7
8/// Result type for HTTP requests.
9#[allow(type_alias_bounds)]
10pub type HttpResult<T: IntoResponse, E: IntoResponse = HttpError> = Result<T, E>;
11
12/// Implemented by the `Reply::body` to convert itself into a format compatible
13/// with `[IntoResponse]`.
14pub trait IntoBody: Body {
15    /// Convert implementing type into an http-compatible body.
16    ///
17    /// # Errors
18    ///
19    /// Returns an error if the body cannot be encoded (for example, if JSON
20    /// serialization fails).
21    fn into_body(self) -> anyhow::Result<Vec<u8>>;
22}
23
24impl<T> IntoResponse for Reply<T>
25where
26    T: IntoBody,
27{
28    fn into_response(self) -> Response {
29        let body = match self.body.into_body() {
30            Ok(v) => v,
31            Err(e) => {
32                return (StatusCode::INTERNAL_SERVER_ERROR, format!("body encoding error: {e}"))
33                    .into_response();
34            }
35        };
36
37        let mut hm = self.headers;
38        if !hm.contains_key(CONTENT_TYPE) {
39            hm.insert(CONTENT_TYPE, HeaderValue::from_static("text/plain; charset=utf-8"));
40        }
41
42        let status = self.status;
43        (status, hm, body).into_response()
44    }
45}
46
47/// Error type for HTTP requests.
48pub struct HttpError {
49    status: StatusCode,
50    error: String,
51}
52
53impl From<crate::Error> for HttpError {
54    fn from(e: crate::Error) -> Self {
55        Self {
56            status: e.status(),
57            error: e.to_string(),
58        }
59    }
60}
61
62impl From<anyhow::Error> for HttpError {
63    fn from(e: anyhow::Error) -> Self {
64        let error = format!("{e}, caused by: {}", e.root_cause());
65        let status =
66            e.downcast_ref().map_or(StatusCode::INTERNAL_SERVER_ERROR, crate::Error::status);
67        Self { status, error }
68    }
69}
70
71impl IntoResponse for HttpError {
72    fn into_response(self) -> axum::response::Response {
73        (self.status, self.error).into_response()
74    }
75}