kit_rs/http/
response.rs

1use bytes::Bytes;
2use http_body_util::Full;
3
4/// HTTP Response builder providing Laravel-like response creation
5pub struct HttpResponse {
6    status: u16,
7    body: String,
8    headers: Vec<(String, String)>,
9}
10
11/// Response type alias - allows using `?` operator for early returns
12pub type Response = Result<HttpResponse, HttpResponse>;
13
14impl HttpResponse {
15    pub fn new() -> Self {
16        Self {
17            status: 200,
18            body: String::new(),
19            headers: Vec::new(),
20        }
21    }
22
23    /// Create a response with a string body
24    pub fn text(body: impl Into<String>) -> Self {
25        Self {
26            status: 200,
27            body: body.into(),
28            headers: vec![("Content-Type".to_string(), "text/plain".to_string())],
29        }
30    }
31
32    /// Create a JSON response from a serde_json::Value
33    pub fn json(body: serde_json::Value) -> Self {
34        Self {
35            status: 200,
36            body: body.to_string(),
37            headers: vec![("Content-Type".to_string(), "application/json".to_string())],
38        }
39    }
40
41    /// Set the HTTP status code
42    pub fn status(mut self, status: u16) -> Self {
43        self.status = status;
44        self
45    }
46
47    /// Add a header to the response
48    pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
49        self.headers.push((name.into(), value.into()));
50        self
51    }
52
53    /// Wrap this response in Ok() for use as Response type
54    pub fn ok(self) -> Response {
55        Ok(self)
56    }
57
58    /// Convert to hyper response
59    pub fn into_hyper(self) -> hyper::Response<Full<Bytes>> {
60        let mut builder = hyper::Response::builder().status(self.status);
61
62        for (name, value) in self.headers {
63            builder = builder.header(name, value);
64        }
65
66        builder
67            .body(Full::new(Bytes::from(self.body)))
68            .unwrap()
69    }
70}
71
72impl Default for HttpResponse {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78/// Extension trait for Response to enable method chaining on macros
79pub trait ResponseExt {
80    fn status(self, code: u16) -> Self;
81    fn header(self, name: impl Into<String>, value: impl Into<String>) -> Self;
82}
83
84impl ResponseExt for Response {
85    fn status(self, code: u16) -> Self {
86        self.map(|r| r.status(code))
87    }
88
89    fn header(self, name: impl Into<String>, value: impl Into<String>) -> Self {
90        self.map(|r| r.header(name, value))
91    }
92}