typeway_server/
response.rs1use bytes::Bytes;
6use http::StatusCode;
7use serde::Serialize;
8
9use crate::body::{body_from_bytes, body_from_string, empty_body, BoxBody};
10
11#[diagnostic::on_unimplemented(
13 message = "`{Self}` cannot be used as an HTTP response",
14 label = "does not implement `IntoResponse`",
15 note = "valid response types include: `&'static str`, `String`, `Json<T>`, `StatusCode`, `(StatusCode, T)`, `Result<T, E>`"
16)]
17pub trait IntoResponse {
18 fn into_response(self) -> http::Response<BoxBody>;
20}
21
22impl IntoResponse for http::Response<BoxBody> {
23 fn into_response(self) -> http::Response<BoxBody> {
24 self
25 }
26}
27
28impl IntoResponse for &'static str {
29 fn into_response(self) -> http::Response<BoxBody> {
30 let body = body_from_bytes(Bytes::from_static(self.as_bytes()));
31 let mut res = http::Response::new(body);
32 res.headers_mut().insert(
33 http::header::CONTENT_TYPE,
34 http::HeaderValue::from_static("text/plain; charset=utf-8"),
35 );
36 res
37 }
38}
39
40impl IntoResponse for String {
41 fn into_response(self) -> http::Response<BoxBody> {
42 let body = body_from_string(self);
43 let mut res = http::Response::new(body);
44 res.headers_mut().insert(
45 http::header::CONTENT_TYPE,
46 http::HeaderValue::from_static("text/plain; charset=utf-8"),
47 );
48 res
49 }
50}
51
52impl IntoResponse for StatusCode {
53 fn into_response(self) -> http::Response<BoxBody> {
54 let mut res = http::Response::new(empty_body());
55 *res.status_mut() = self;
56 res
57 }
58}
59
60impl<T: IntoResponse> IntoResponse for (StatusCode, T) {
61 fn into_response(self) -> http::Response<BoxBody> {
62 let mut res = self.1.into_response();
63 *res.status_mut() = self.0;
64 res
65 }
66}
67
68impl<T: IntoResponse, E: IntoResponse> IntoResponse for Result<T, E> {
69 fn into_response(self) -> http::Response<BoxBody> {
70 match self {
71 Ok(v) => v.into_response(),
72 Err(e) => e.into_response(),
73 }
74 }
75}
76
77impl IntoResponse for Bytes {
78 fn into_response(self) -> http::Response<BoxBody> {
79 let body = body_from_bytes(self);
80 let mut res = http::Response::new(body);
81 res.headers_mut().insert(
82 http::header::CONTENT_TYPE,
83 http::HeaderValue::from_static("application/octet-stream"),
84 );
85 res
86 }
87}
88
89pub struct Json<T>(pub T);
106
107impl<T: Serialize> IntoResponse for Json<T> {
108 fn into_response(self) -> http::Response<BoxBody> {
109 match serde_json::to_vec(&self.0) {
110 Ok(bytes) => {
111 let body = body_from_bytes(Bytes::from(bytes));
112 let mut res = http::Response::new(body);
113 res.headers_mut().insert(
114 http::header::CONTENT_TYPE,
115 http::HeaderValue::from_static("application/json"),
116 );
117 res
118 }
119 Err(e) => {
120 let body = body_from_string(format!("JSON serialization error: {e}"));
121 let mut res = http::Response::new(body);
122 *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
123 res
124 }
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn static_str_response() {
135 let res = "hello".into_response();
136 assert_eq!(res.status(), StatusCode::OK);
137 assert_eq!(
138 res.headers().get("content-type").unwrap(),
139 "text/plain; charset=utf-8"
140 );
141 }
142
143 #[test]
144 fn string_response() {
145 let res = "hello".to_string().into_response();
146 assert_eq!(res.status(), StatusCode::OK);
147 }
148
149 #[test]
150 fn status_code_response() {
151 let res = StatusCode::NOT_FOUND.into_response();
152 assert_eq!(res.status(), StatusCode::NOT_FOUND);
153 }
154
155 #[test]
156 fn tuple_status_body() {
157 let res = (StatusCode::CREATED, "done").into_response();
158 assert_eq!(res.status(), StatusCode::CREATED);
159 }
160
161 #[test]
162 fn result_ok() {
163 let res: Result<&str, StatusCode> = Ok("good");
164 let res = res.into_response();
165 assert_eq!(res.status(), StatusCode::OK);
166 }
167
168 #[test]
169 fn result_err() {
170 let res: Result<&str, StatusCode> = Err(StatusCode::BAD_REQUEST);
171 let res = res.into_response();
172 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
173 }
174
175 #[test]
176 fn json_response() {
177 let res = Json(serde_json::json!({"id": 1})).into_response();
178 assert_eq!(res.status(), StatusCode::OK);
179 assert_eq!(
180 res.headers().get("content-type").unwrap(),
181 "application/json"
182 );
183 }
184}