1use crate::cookies::Cookie;
4use crate::error::Error;
5use bytes::Bytes;
6use http::StatusCode;
7use serde::Serialize;
8
9pub struct Response {
11 pub status: StatusCode,
12 pub headers: http::HeaderMap,
13 pub body: Bytes,
14 cookies: Vec<Cookie>,
15}
16
17impl Response {
18 pub fn new(status: StatusCode) -> Self {
19 Self {
20 status,
21 headers: http::HeaderMap::new(),
22 body: Bytes::new(),
23 cookies: Vec::new(),
24 }
25 }
26
27 pub fn cookie(mut self, cookie: Cookie) -> Self {
29 self.cookies.push(cookie);
30 self
31 }
32
33 pub fn ok() -> Self {
34 Self::new(StatusCode::OK)
35 }
36
37 pub fn with_status(mut self, status: StatusCode) -> Self {
38 self.status = status;
39 self
40 }
41
42 pub fn with_body(mut self, body: impl Into<Bytes>) -> Self {
43 self.body = body.into();
44 self
45 }
46
47 pub fn with_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
48 let key = key.into();
49 let value = value.into();
50
51 if let (Ok(header_name), Ok(header_value)) = (
53 http::HeaderName::from_bytes(key.as_bytes()),
54 http::HeaderValue::from_str(&value),
55 ) {
56 self.headers.insert(header_name, header_value);
57 } else {
58 eprintln!("Warning: Invalid header {}={}", key, value);
59 }
60 self
61 }
62
63 pub fn json<T: Serialize>(data: T) -> Self {
64 match serde_json::to_vec(&data) {
65 Ok(body) => Self::ok()
66 .with_header("content-type", "application/json")
67 .with_body(body),
68 Err(e) => {
69 eprintln!("JSON serialization error: {}", e);
70 Self::new(StatusCode::INTERNAL_SERVER_ERROR)
71 .with_header("content-type", "application/json")
72 .with_body("{\"error\":\"Internal serialization error\"}")
73 }
74 }
75 }
76
77 pub fn text(text: impl Into<String>) -> Self {
78 Self::ok()
79 .with_header("content-type", "text/plain")
80 .with_body(text.into())
81 }
82
83 pub fn html(html: impl Into<String>) -> Self {
85 Self::ok()
86 .with_header("content-type", "text/html; charset=utf-8")
87 .with_body(html.into())
88 }
89
90 pub fn redirect(location: impl Into<String>) -> Self {
92 Self::new(StatusCode::SEE_OTHER).with_header("location", location)
93 }
94
95 pub fn redirect_permanent(location: impl Into<String>) -> Self {
97 Self::new(StatusCode::PERMANENT_REDIRECT).with_header("location", location)
98 }
99
100 pub fn from_error(error: Error) -> Self {
101 let status = error.status();
102 let mut body = serde_json::json!({
103 "error": error.message(),
104 "status": error.status_code(),
105 });
106 if let Error::Validation(fields) = &error {
107 let mut by_field = serde_json::Map::new();
109 for f in fields {
110 if let Some(list) = by_field
111 .entry(f.field.clone())
112 .or_insert_with(|| serde_json::Value::Array(Vec::new()))
113 .as_array_mut()
114 {
115 list.push(serde_json::Value::String(f.message.clone()));
116 }
117 }
118 body["fields"] = serde_json::Value::Object(by_field);
119 }
120 let body_bytes =
121 serde_json::to_vec(&body).unwrap_or_else(|_| b"{\"error\":\"Unknown error\"}".to_vec());
122 Self::new(status)
123 .with_header("content-type", "application/json")
124 .with_body(body_bytes)
125 }
126
127 pub(crate) fn into_hyper(self) -> hyper::Response<http_body_util::Full<Bytes>> {
128 let mut builder = hyper::Response::builder().status(self.status);
129
130 for (key, value) in self.headers.iter() {
131 builder = builder.header(key, value);
132 }
133
134 for cookie in self.cookies {
136 builder = builder.header("set-cookie", cookie.to_header_value());
137 }
138
139 builder
140 .body(http_body_util::Full::new(self.body))
141 .unwrap_or_else(|e| {
142 eprintln!("Failed to build response: {}", e);
143 hyper::Response::builder()
144 .status(StatusCode::INTERNAL_SERVER_ERROR)
145 .body(http_body_util::Full::new(Bytes::from(
146 "Internal Server Error",
147 )))
148 .unwrap()
149 })
150 }
151}
152
153pub struct Json<T>(pub T);
155
156impl<T: Serialize> From<Json<T>> for Response {
157 fn from(json: Json<T>) -> Self {
158 Response::json(json.0)
159 }
160}