Skip to main content

oxidite_core/
response.rs

1use crate::types::OxiditeResponse;
2use crate::error::Error;
3use http_body_util::{Full, BodyExt};
4use bytes::Bytes;
5use hyper::Response;
6use hyper::header::{HeaderValue, CONTENT_TYPE, SERVER};
7use http::StatusCode;
8
9pub(crate) const SERVER_HEADER_VALUE: &str = concat!("Oxidite/", env!("CARGO_PKG_VERSION"));
10
11impl OxiditeResponse {
12    /// Create a JSON response
13    pub fn json<T: serde::Serialize>(data: T) -> Self {
14        match serde_json::to_vec(&data) {
15            Ok(json_bytes) => {
16                let res = Response::builder()
17                    .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
18                    .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
19                    .body(Full::new(Bytes::from(json_bytes)).map_err(|e| match e {}).boxed())
20                    .unwrap();
21                Self(res)
22            },
23            Err(_) => {
24                let res = Response::builder()
25                    .status(StatusCode::INTERNAL_SERVER_ERROR)
26                    .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
27                    .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
28                    .body(Full::new(Bytes::from("{\"error\":\"Internal Server Error\"}".as_bytes().to_vec())).map_err(|e| match e {}).boxed())
29                    .unwrap();
30                Self(res)
31            },
32        }
33    }
34
35    /// Create an HTML response
36    pub fn html(body: impl Into<String>) -> Self {
37        let res = Response::builder()
38            .header(CONTENT_TYPE, HeaderValue::from_static("text/html"))
39            .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
40            .body(Full::new(Bytes::from(body.into())).map_err(|e| match e {}).boxed())
41            .unwrap();
42        Self(res)
43    }
44
45    /// Create a plain text response
46    pub fn text(body: impl Into<String>) -> Self {
47        let res = Response::builder()
48            .header(CONTENT_TYPE, HeaderValue::from_static("text/plain"))
49            .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
50            .body(Full::new(Bytes::from(body.into())).map_err(|e| match e {}).boxed())
51            .unwrap();
52        Self(res)
53    }
54
55    /// Create an empty response with 200 OK status
56    pub fn ok() -> Self {
57        let res = Response::builder()
58            .status(StatusCode::OK)
59            .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
60            .body(Full::new(Bytes::new()).map_err(|e| match e {}).boxed())
61            .unwrap();
62        Self(res)
63    }
64
65    /// Create an empty response with 204 No Content status
66    pub fn no_content() -> Self {
67        let res = Response::builder()
68            .status(StatusCode::NO_CONTENT)
69            .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
70            .body(Full::new(Bytes::new()).map_err(|e| match e {}).boxed())
71            .unwrap();
72        Self(res)
73    }
74}
75
76impl From<Error> for OxiditeResponse {
77    fn from(error: Error) -> Self {
78        let status = error.status_code();
79        let body = serde_json::json!({
80            "error": error.to_string()
81        });
82
83        let fallback = format!(r#"{{"error":"{}"}}"#, status);
84        let json_bytes = serde_json::to_vec(&body).unwrap_or_else(|_| fallback.into_bytes());
85
86        let res = Response::builder()
87            .status(status)
88            .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
89            .header(SERVER, HeaderValue::from_static(SERVER_HEADER_VALUE))
90            .body(Full::new(Bytes::from(json_bytes)).map_err(|e| match e {}).boxed())
91            .unwrap();
92        Self(res)
93    }
94}