/rust/registry/src/index.crates.io-1949cf8c6b5b557f/axum-0.8.8/src/response/mod.rs
Line | Count | Source |
1 | | #![doc = include_str!("../docs/response.md")] |
2 | | |
3 | | use http::{header, HeaderValue, StatusCode}; |
4 | | |
5 | | mod redirect; |
6 | | |
7 | | pub mod sse; |
8 | | |
9 | | #[doc(no_inline)] |
10 | | #[cfg(feature = "json")] |
11 | | pub use crate::Json; |
12 | | |
13 | | #[cfg(feature = "form")] |
14 | | #[doc(no_inline)] |
15 | | pub use crate::form::Form; |
16 | | |
17 | | #[doc(no_inline)] |
18 | | pub use crate::Extension; |
19 | | |
20 | | #[doc(inline)] |
21 | | pub use axum_core::response::{ |
22 | | AppendHeaders, ErrorResponse, IntoResponse, IntoResponseParts, Response, ResponseParts, Result, |
23 | | }; |
24 | | |
25 | | #[doc(inline)] |
26 | | pub use self::redirect::Redirect; |
27 | | |
28 | | #[doc(inline)] |
29 | | pub use sse::Sse; |
30 | | |
31 | | /// An HTML response. |
32 | | /// |
33 | | /// Will automatically get `Content-Type: text/html`. |
34 | | #[derive(Clone, Copy, Debug)] |
35 | | #[must_use] |
36 | | pub struct Html<T>(pub T); |
37 | | |
38 | | impl<T> IntoResponse for Html<T> |
39 | | where |
40 | | T: IntoResponse, |
41 | | { |
42 | 0 | fn into_response(self) -> Response { |
43 | 0 | ( |
44 | 0 | [( |
45 | 0 | header::CONTENT_TYPE, |
46 | 0 | HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()), |
47 | 0 | )], |
48 | 0 | self.0, |
49 | 0 | ) |
50 | 0 | .into_response() |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl<T> From<T> for Html<T> { |
55 | 0 | fn from(inner: T) -> Self { |
56 | 0 | Self(inner) |
57 | 0 | } |
58 | | } |
59 | | |
60 | | /// An empty response with 204 No Content status. |
61 | | /// |
62 | | /// Due to historical and implementation reasons, the `IntoResponse` implementation of `()` |
63 | | /// (unit type) returns an empty response with 200 [`StatusCode::OK`] status. |
64 | | /// If you specifically want a 204 [`StatusCode::NO_CONTENT`] status, you can use either `StatusCode` type |
65 | | /// directly, or this shortcut struct for self-documentation. |
66 | | /// |
67 | | /// ``` |
68 | | /// use axum::{extract::Path, response::NoContent}; |
69 | | /// |
70 | | /// async fn delete_user(Path(user): Path<String>) -> Result<NoContent, String> { |
71 | | /// // ...access database... |
72 | | /// # drop(user); |
73 | | /// Ok(NoContent) |
74 | | /// } |
75 | | /// ``` |
76 | | #[derive(Debug, Clone, Copy)] |
77 | | pub struct NoContent; |
78 | | |
79 | | impl IntoResponse for NoContent { |
80 | 0 | fn into_response(self) -> Response { |
81 | 0 | StatusCode::NO_CONTENT.into_response() |
82 | 0 | } |
83 | | } |
84 | | |
85 | | #[cfg(test)] |
86 | | mod tests { |
87 | | use crate::extract::Extension; |
88 | | use crate::{routing::get, Router}; |
89 | | use axum_core::response::IntoResponse; |
90 | | use http::HeaderMap; |
91 | | use http::{StatusCode, Uri}; |
92 | | |
93 | | // just needs to compile |
94 | | #[allow(dead_code)] |
95 | | fn impl_trait_result_works() { |
96 | | async fn impl_trait_ok() -> Result<impl IntoResponse, ()> { |
97 | | Ok(()) |
98 | | } |
99 | | |
100 | | async fn impl_trait_err() -> Result<(), impl IntoResponse> { |
101 | | Err(()) |
102 | | } |
103 | | |
104 | | async fn impl_trait_both(uri: Uri) -> Result<impl IntoResponse, impl IntoResponse> { |
105 | | if uri.path() == "/" { |
106 | | Ok(()) |
107 | | } else { |
108 | | Err(()) |
109 | | } |
110 | | } |
111 | | |
112 | | async fn impl_trait(uri: Uri) -> impl IntoResponse { |
113 | | if uri.path() == "/" { |
114 | | Ok(()) |
115 | | } else { |
116 | | Err(()) |
117 | | } |
118 | | } |
119 | | |
120 | | _ = Router::<()>::new() |
121 | | .route("/", get(impl_trait_ok)) |
122 | | .route("/", get(impl_trait_err)) |
123 | | .route("/", get(impl_trait_both)) |
124 | | .route("/", get(impl_trait)); |
125 | | } |
126 | | |
127 | | // just needs to compile |
128 | | #[allow(dead_code)] |
129 | | fn tuple_responses() { |
130 | | async fn status() -> impl IntoResponse { |
131 | | StatusCode::OK |
132 | | } |
133 | | |
134 | | async fn status_headermap() -> impl IntoResponse { |
135 | | (StatusCode::OK, HeaderMap::new()) |
136 | | } |
137 | | |
138 | | async fn status_header_array() -> impl IntoResponse { |
139 | | (StatusCode::OK, [("content-type", "text/plain")]) |
140 | | } |
141 | | |
142 | | async fn status_headermap_body() -> impl IntoResponse { |
143 | | (StatusCode::OK, HeaderMap::new(), String::new()) |
144 | | } |
145 | | |
146 | | async fn status_header_array_body() -> impl IntoResponse { |
147 | | ( |
148 | | StatusCode::OK, |
149 | | [("content-type", "text/plain")], |
150 | | String::new(), |
151 | | ) |
152 | | } |
153 | | |
154 | | async fn status_headermap_impl_into_response() -> impl IntoResponse { |
155 | | (StatusCode::OK, HeaderMap::new(), impl_into_response()) |
156 | | } |
157 | | |
158 | | async fn status_header_array_impl_into_response() -> impl IntoResponse { |
159 | | ( |
160 | | StatusCode::OK, |
161 | | [("content-type", "text/plain")], |
162 | | impl_into_response(), |
163 | | ) |
164 | | } |
165 | | |
166 | | fn impl_into_response() -> impl IntoResponse {} |
167 | | |
168 | | async fn status_header_array_extension_body() -> impl IntoResponse { |
169 | | ( |
170 | | StatusCode::OK, |
171 | | [("content-type", "text/plain")], |
172 | | Extension(1), |
173 | | String::new(), |
174 | | ) |
175 | | } |
176 | | |
177 | | async fn status_header_array_extension_mixed_body() -> impl IntoResponse { |
178 | | ( |
179 | | StatusCode::OK, |
180 | | [("content-type", "text/plain")], |
181 | | Extension(1), |
182 | | HeaderMap::new(), |
183 | | String::new(), |
184 | | ) |
185 | | } |
186 | | |
187 | | // |
188 | | |
189 | | async fn headermap() -> impl IntoResponse { |
190 | | HeaderMap::new() |
191 | | } |
192 | | |
193 | | async fn header_array() -> impl IntoResponse { |
194 | | [("content-type", "text/plain")] |
195 | | } |
196 | | |
197 | | async fn headermap_body() -> impl IntoResponse { |
198 | | (HeaderMap::new(), String::new()) |
199 | | } |
200 | | |
201 | | async fn header_array_body() -> impl IntoResponse { |
202 | | ([("content-type", "text/plain")], String::new()) |
203 | | } |
204 | | |
205 | | async fn headermap_impl_into_response() -> impl IntoResponse { |
206 | | (HeaderMap::new(), impl_into_response()) |
207 | | } |
208 | | |
209 | | async fn header_array_impl_into_response() -> impl IntoResponse { |
210 | | ([("content-type", "text/plain")], impl_into_response()) |
211 | | } |
212 | | |
213 | | async fn header_array_extension_body() -> impl IntoResponse { |
214 | | ( |
215 | | [("content-type", "text/plain")], |
216 | | Extension(1), |
217 | | String::new(), |
218 | | ) |
219 | | } |
220 | | |
221 | | async fn header_array_extension_mixed_body() -> impl IntoResponse { |
222 | | ( |
223 | | [("content-type", "text/plain")], |
224 | | Extension(1), |
225 | | HeaderMap::new(), |
226 | | String::new(), |
227 | | ) |
228 | | } |
229 | | |
230 | | _ = Router::<()>::new() |
231 | | .route("/", get(status)) |
232 | | .route("/", get(status_headermap)) |
233 | | .route("/", get(status_header_array)) |
234 | | .route("/", get(status_headermap_body)) |
235 | | .route("/", get(status_header_array_body)) |
236 | | .route("/", get(status_headermap_impl_into_response)) |
237 | | .route("/", get(status_header_array_impl_into_response)) |
238 | | .route("/", get(status_header_array_extension_body)) |
239 | | .route("/", get(status_header_array_extension_mixed_body)) |
240 | | .route("/", get(headermap)) |
241 | | .route("/", get(header_array)) |
242 | | .route("/", get(headermap_body)) |
243 | | .route("/", get(header_array_body)) |
244 | | .route("/", get(headermap_impl_into_response)) |
245 | | .route("/", get(header_array_impl_into_response)) |
246 | | .route("/", get(header_array_extension_body)) |
247 | | .route("/", get(header_array_extension_mixed_body)); |
248 | | } |
249 | | |
250 | | #[test] |
251 | | fn no_content() { |
252 | | assert_eq!( |
253 | | super::NoContent.into_response().status(), |
254 | | StatusCode::NO_CONTENT, |
255 | | ) |
256 | | } |
257 | | } |