axum/response/
mod.rs
1#![doc = include_str!("../docs/response.md")]
2
3use axum_core::body::Body;
4use http::{header, HeaderValue};
5
6mod redirect;
7
8#[cfg(feature = "tokio")]
9pub mod sse;
10
11#[doc(no_inline)]
12#[cfg(feature = "json")]
13pub use crate::Json;
14
15#[cfg(feature = "form")]
16#[doc(no_inline)]
17pub use crate::form::Form;
18
19#[doc(no_inline)]
20pub use crate::Extension;
21
22#[doc(inline)]
23pub use axum_core::response::{
24 AppendHeaders, ErrorResponse, IntoResponse, IntoResponseParts, Response, ResponseParts, Result,
25};
26
27#[doc(inline)]
28pub use self::redirect::Redirect;
29
30#[doc(inline)]
31#[cfg(feature = "tokio")]
32pub use sse::Sse;
33
34#[derive(Clone, Copy, Debug)]
38#[must_use]
39pub struct Html<T>(pub T);
40
41impl<T> IntoResponse for Html<T>
42where
43 T: Into<Body>,
44{
45 fn into_response(self) -> Response {
46 (
47 [(
48 header::CONTENT_TYPE,
49 HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()),
50 )],
51 self.0.into(),
52 )
53 .into_response()
54 }
55}
56
57impl<T> From<T> for Html<T> {
58 fn from(inner: T) -> Self {
59 Self(inner)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::extract::Extension;
66 use crate::{routing::get, Router};
67 use axum_core::response::IntoResponse;
68 use http::HeaderMap;
69 use http::{StatusCode, Uri};
70
71 #[allow(dead_code)]
73 fn impl_trait_result_works() {
74 async fn impl_trait_ok() -> Result<impl IntoResponse, ()> {
75 Ok(())
76 }
77
78 async fn impl_trait_err() -> Result<(), impl IntoResponse> {
79 Err(())
80 }
81
82 async fn impl_trait_both(uri: Uri) -> Result<impl IntoResponse, impl IntoResponse> {
83 if uri.path() == "/" {
84 Ok(())
85 } else {
86 Err(())
87 }
88 }
89
90 async fn impl_trait(uri: Uri) -> impl IntoResponse {
91 if uri.path() == "/" {
92 Ok(())
93 } else {
94 Err(())
95 }
96 }
97
98 _ = Router::<()>::new()
99 .route("/", get(impl_trait_ok))
100 .route("/", get(impl_trait_err))
101 .route("/", get(impl_trait_both))
102 .route("/", get(impl_trait));
103 }
104
105 #[allow(dead_code)]
107 fn tuple_responses() {
108 async fn status() -> impl IntoResponse {
109 StatusCode::OK
110 }
111
112 async fn status_headermap() -> impl IntoResponse {
113 (StatusCode::OK, HeaderMap::new())
114 }
115
116 async fn status_header_array() -> impl IntoResponse {
117 (StatusCode::OK, [("content-type", "text/plain")])
118 }
119
120 async fn status_headermap_body() -> impl IntoResponse {
121 (StatusCode::OK, HeaderMap::new(), String::new())
122 }
123
124 async fn status_header_array_body() -> impl IntoResponse {
125 (
126 StatusCode::OK,
127 [("content-type", "text/plain")],
128 String::new(),
129 )
130 }
131
132 async fn status_headermap_impl_into_response() -> impl IntoResponse {
133 (StatusCode::OK, HeaderMap::new(), impl_into_response())
134 }
135
136 async fn status_header_array_impl_into_response() -> impl IntoResponse {
137 (
138 StatusCode::OK,
139 [("content-type", "text/plain")],
140 impl_into_response(),
141 )
142 }
143
144 fn impl_into_response() -> impl IntoResponse {}
145
146 async fn status_header_array_extension_body() -> impl IntoResponse {
147 (
148 StatusCode::OK,
149 [("content-type", "text/plain")],
150 Extension(1),
151 String::new(),
152 )
153 }
154
155 async fn status_header_array_extension_mixed_body() -> impl IntoResponse {
156 (
157 StatusCode::OK,
158 [("content-type", "text/plain")],
159 Extension(1),
160 HeaderMap::new(),
161 String::new(),
162 )
163 }
164
165 async fn headermap() -> impl IntoResponse {
168 HeaderMap::new()
169 }
170
171 async fn header_array() -> impl IntoResponse {
172 [("content-type", "text/plain")]
173 }
174
175 async fn headermap_body() -> impl IntoResponse {
176 (HeaderMap::new(), String::new())
177 }
178
179 async fn header_array_body() -> impl IntoResponse {
180 ([("content-type", "text/plain")], String::new())
181 }
182
183 async fn headermap_impl_into_response() -> impl IntoResponse {
184 (HeaderMap::new(), impl_into_response())
185 }
186
187 async fn header_array_impl_into_response() -> impl IntoResponse {
188 ([("content-type", "text/plain")], impl_into_response())
189 }
190
191 async fn header_array_extension_body() -> impl IntoResponse {
192 (
193 [("content-type", "text/plain")],
194 Extension(1),
195 String::new(),
196 )
197 }
198
199 async fn header_array_extension_mixed_body() -> impl IntoResponse {
200 (
201 [("content-type", "text/plain")],
202 Extension(1),
203 HeaderMap::new(),
204 String::new(),
205 )
206 }
207
208 _ = Router::<()>::new()
209 .route("/", get(status))
210 .route("/", get(status_headermap))
211 .route("/", get(status_header_array))
212 .route("/", get(status_headermap_body))
213 .route("/", get(status_header_array_body))
214 .route("/", get(status_headermap_impl_into_response))
215 .route("/", get(status_header_array_impl_into_response))
216 .route("/", get(status_header_array_extension_body))
217 .route("/", get(status_header_array_extension_mixed_body))
218 .route("/", get(headermap))
219 .route("/", get(header_array))
220 .route("/", get(headermap_body))
221 .route("/", get(header_array_body))
222 .route("/", get(headermap_impl_into_response))
223 .route("/", get(header_array_impl_into_response))
224 .route("/", get(header_array_extension_body))
225 .route("/", get(header_array_extension_mixed_body));
226 }
227}