tork_core/response/
mod.rs1use bytes::Bytes;
4use http::header::{HeaderValue, CONTENT_TYPE};
5use http::StatusCode;
6
7use crate::body::RespBody;
8
9pub mod json;
10
11pub use json::{json_response, Json};
12
13pub type Response = http::Response<RespBody>;
15
16pub trait IntoResponse {
25 fn into_response(self) -> Response;
27}
28
29pub(crate) fn with_body(status: StatusCode, content_type: &'static str, body: Bytes) -> Response {
31 let mut response = http::Response::new(RespBody::new(body));
32 *response.status_mut() = status;
33 response
34 .headers_mut()
35 .insert(CONTENT_TYPE, HeaderValue::from_static(content_type));
36 response
37}
38
39pub fn bytes_response(status: StatusCode, content_type: &'static str, body: Bytes) -> Response {
44 with_body(status, content_type, body)
45}
46
47pub(crate) async fn into_body_bytes(response: Response) -> (http::response::Parts, Bytes) {
52 use http_body_util::BodyExt;
53 let (parts, body) = response.into_parts();
54 let bytes = body
55 .collect()
56 .await
57 .map(|collected| collected.to_bytes())
58 .unwrap_or_default();
59 (parts, bytes)
60}
61
62pub(crate) fn empty(status: StatusCode) -> Response {
64 let mut response = http::Response::new(RespBody::new(Bytes::new()));
65 *response.status_mut() = status;
66 response
67}
68
69impl IntoResponse for Response {
70 fn into_response(self) -> Response {
71 self
72 }
73}
74
75impl IntoResponse for StatusCode {
76 fn into_response(self) -> Response {
77 empty(self)
78 }
79}
80
81impl IntoResponse for () {
82 fn into_response(self) -> Response {
83 empty(StatusCode::OK)
84 }
85}
86
87impl<T, E> IntoResponse for core::result::Result<T, E>
88where
89 T: IntoResponse,
90 E: Into<crate::error::Error>,
91{
92 fn into_response(self) -> Response {
93 match self {
94 Ok(value) => value.into_response(),
95 Err(error) => error.into().into_response(),
96 }
97 }
98}
99
100#[doc(hidden)]
111pub fn __finish<T, E>(
112 result: core::result::Result<T, E>,
113 status: StatusCode,
114) -> crate::error::Result<Response>
115where
116 T: serde::Serialize,
117 E: Into<crate::error::Error>,
118{
119 match result {
120 Ok(value) => Ok(json::json_response(status, &value)),
121 Err(error) => Err(error.into()),
122 }
123}
124
125#[doc(hidden)]
132pub fn __finish_into<T, U, E>(
133 result: core::result::Result<T, E>,
134 status: StatusCode,
135) -> crate::error::Result<Response>
136where
137 U: From<T> + serde::Serialize,
138 E: Into<crate::error::Error>,
139{
140 match result {
141 Ok(value) => Ok(json::json_response(status, &U::from(value))),
142 Err(error) => Err(error.into()),
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::error::Error;
150 use bytes::Bytes;
151 use serde::Serialize;
152
153 #[derive(Serialize)]
154 struct Payload {
155 id: i64,
156 }
157
158 #[derive(Serialize)]
159 struct RawPayload {
160 id: i64,
161 }
162
163 impl From<RawPayload> for Payload {
164 fn from(value: RawPayload) -> Self {
165 Self { id: value.id }
166 }
167 }
168
169 #[tokio::test]
170 async fn status_code_and_unit_into_response_are_empty() {
171 let status = StatusCode::NO_CONTENT.into_response();
172 let unit = ().into_response();
173
174 let (status_parts, status_body) = into_body_bytes(status).await;
175 let (unit_parts, unit_body) = into_body_bytes(unit).await;
176
177 assert_eq!(status_parts.status, StatusCode::NO_CONTENT);
178 assert_eq!(status_body, Bytes::new());
179 assert_eq!(unit_parts.status, StatusCode::OK);
180 assert_eq!(unit_body, Bytes::new());
181 }
182
183 #[tokio::test]
184 async fn finish_helpers_serialize_success_values() {
185 let direct = __finish::<_, Error>(Ok(Payload { id: 7 }), StatusCode::CREATED).unwrap();
186 let mapped =
187 __finish_into::<_, Payload, Error>(Ok(RawPayload { id: 9 }), StatusCode::ACCEPTED)
188 .unwrap();
189
190 let (direct_parts, direct_body) = into_body_bytes(direct).await;
191 let (mapped_parts, mapped_body) = into_body_bytes(mapped).await;
192
193 assert_eq!(direct_parts.status, StatusCode::CREATED);
194 assert_eq!(mapped_parts.status, StatusCode::ACCEPTED);
195 assert_eq!(direct_body, Bytes::from_static(br#"{"id":7}"#));
196 assert_eq!(mapped_body, Bytes::from_static(br#"{"id":9}"#));
197 }
198
199 #[test]
200 fn result_into_response_and_finish_helpers_propagate_errors() {
201 let error = Error::bad_request("bad");
202
203 let response =
204 core::result::Result::<StatusCode, _>::Err(Error::bad_request("bad")).into_response();
205 assert_eq!(response.status(), StatusCode::BAD_REQUEST);
206
207 let finish = __finish::<Payload, _>(Err(error), StatusCode::OK)
208 .err()
209 .expect("expected handler error");
210 assert_eq!(finish.message(), "bad");
211 }
212}