1Types and traits for generating responses.
2
3# Table of contents
4
5- [Building responses](#building-responses)
6- [Returning different response types](#returning-different-response-types)
7- [Regarding `impl IntoResponse`](#regarding-impl-intoresponse)
8
9# Building responses
10
11Anything that implements [`IntoResponse`] can be returned from a handler. axum
12provides implementations for common types:
13
14```rust,no_run
15use axum::{
16    Json,
17    response::{Html, IntoResponse},
18    http::{StatusCode, Uri, header::{self, HeaderMap, HeaderName}},
19};
20
21// `()` gives an empty response
22async fn empty() {}
23
24// String will get a `text/plain; charset=utf-8` content-type
25async fn plain_text(uri: Uri) -> String {
26    format!("Hi from {}", uri.path())
27}
28
29// Bytes will get a `application/octet-stream` content-type
30async fn bytes() -> Vec<u8> {
31    vec![1, 2, 3, 4]
32}
33
34// `Json` will get a `application/json` content-type and work with anything that
35// implements `serde::Serialize`
36async fn json() -> Json<Vec<String>> {
37    Json(vec!["foo".to_owned(), "bar".to_owned()])
38}
39
40// `Html` will get a `text/html` content-type
41async fn html() -> Html<&'static str> {
42    Html("<p>Hello, World!</p>")
43}
44
45// `StatusCode` gives an empty response with that status code
46async fn status() -> StatusCode {
47    StatusCode::NOT_FOUND
48}
49
50// `HeaderMap` gives an empty response with some headers
51async fn headers() -> HeaderMap {
52    let mut headers = HeaderMap::new();
53    headers.insert(header::SERVER, "axum".parse().unwrap());
54    headers
55}
56
57// An array of tuples also gives headers
58async fn array_headers() -> [(HeaderName, &'static str); 2] {
59    [
60        (header::SERVER, "axum"),
61        (header::CONTENT_TYPE, "text/plain")
62    ]
63}
64
65// Use `impl IntoResponse` to avoid writing the whole type
66async fn impl_trait() -> impl IntoResponse {
67    [
68        (header::SERVER, "axum"),
69        (header::CONTENT_TYPE, "text/plain")
70    ]
71}
72```
73
74Additionally you can return tuples to build more complex responses from
75individual parts.
76
77```rust,no_run
78use axum::{
79    Json,
80    response::IntoResponse,
81    http::{StatusCode, HeaderMap, Uri, header},
82    extract::Extension,
83};
84
85// `(StatusCode, impl IntoResponse)` will override the status code of the response
86async fn with_status(uri: Uri) -> (StatusCode, String) {
87    (StatusCode::NOT_FOUND, format!("Not Found: {}", uri.path()))
88}
89
90// Use `impl IntoResponse` to avoid having to type the whole type
91async fn impl_trait(uri: Uri) -> impl IntoResponse {
92    (StatusCode::NOT_FOUND, format!("Not Found: {}", uri.path()))
93}
94
95// `(HeaderMap, impl IntoResponse)` to add additional headers
96async fn with_headers() -> impl IntoResponse {
97    let mut headers = HeaderMap::new();
98    headers.insert(header::CONTENT_TYPE, "text/plain".parse().unwrap());
99    (headers, "foo")
100}
101
102// Or an array of tuples to more easily build the headers
103async fn with_array_headers() -> impl IntoResponse {
104    ([(header::CONTENT_TYPE, "text/plain")], "foo")
105}
106
107// Use string keys for custom headers
108async fn with_array_headers_custom() -> impl IntoResponse {
109    ([("x-custom", "custom")], "foo")
110}
111
112// `(StatusCode, headers, impl IntoResponse)` to set status and add headers
113// `headers` can be either a `HeaderMap` or an array of tuples
114async fn with_status_and_array_headers() -> impl IntoResponse {
115    (
116        StatusCode::NOT_FOUND,
117        [(header::CONTENT_TYPE, "text/plain")],
118        "foo",
119    )
120}
121
122// `(Extension<_>, impl IntoResponse)` to set response extensions
123async fn with_status_extensions() -> impl IntoResponse {
124    (
125        Extension(Foo("foo")),
126        "foo",
127    )
128}
129
130struct Foo(&'static str);
131
132// Or mix and match all the things
133async fn all_the_things(uri: Uri) -> impl IntoResponse {
134    let mut header_map = HeaderMap::new();
135    if uri.path() == "/" {
136        header_map.insert(header::SERVER, "axum".parse().unwrap());
137    }
138
139    (
140        // set status code
141        StatusCode::NOT_FOUND,
142        // headers with an array
143        [("x-custom", "custom")],
144        // some extensions
145        Extension(Foo("foo")),
146        Extension(Foo("bar")),
147        // more headers, built dynamically
148        header_map,
149        // and finally the body
150        "foo",
151    )
152}
153```
154
155In general you can return tuples like:
156
157- `(StatusCode, impl IntoResponse)`
158- `(Parts, impl IntoResponse)`
159- `(Response<()>, impl IntoResponse)`
160- `(T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`].
161- `(StatusCode, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`].
162- `(Parts, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`].
163- `(Response<()>, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`].
164
165This means you cannot accidentally override the status or body as [`IntoResponseParts`] only allows
166setting headers and extensions.
167
168Use [`Response`](crate::response::Response) for more low level control:
169
170```rust,no_run
171use axum::{
172    Json,
173    response::{IntoResponse, Response},
174    body::{Full, Bytes},
175    http::StatusCode,
176};
177
178async fn response() -> Response<Full<Bytes>> {
179    Response::builder()
180        .status(StatusCode::NOT_FOUND)
181        .header("x-foo", "custom header")
182        .body(Full::from("not found"))
183        .unwrap()
184}
185```
186
187# Returning different response types
188
189If you need to return multiple response types, and `Result<T, E>` isn't appropriate, you can call
190`.into_response()` to turn things into `axum::response::Response`:
191
192```rust
193use axum::{
194    response::{IntoResponse, Redirect, Response},
195    http::StatusCode,
196};
197
198async fn handle() -> Response {
199    if something() {
200        "All good!".into_response()
201    } else if something_else() {
202        (
203            StatusCode::INTERNAL_SERVER_ERROR,
204            "Something went wrong...",
205        ).into_response()
206    } else {
207        Redirect::to("/").into_response()
208    }
209}
210
211fn something() -> bool {
212    // ...
213    # true
214}
215
216fn something_else() -> bool {
217    // ...
218    # true
219}
220```
221
222# Regarding `impl IntoResponse`
223
224You can use `impl IntoResponse` as the return type from handlers to avoid
225typing large types. For example
226
227```rust
228use axum::http::StatusCode;
229
230async fn handler() -> (StatusCode, [(&'static str, &'static str); 1], &'static str) {
231    (StatusCode::OK, [("x-foo", "bar")], "Hello, World!")
232}
233```
234
235Becomes easier using `impl IntoResponse`:
236
237```rust
238use axum::{http::StatusCode, response::IntoResponse};
239
240async fn impl_into_response() -> impl IntoResponse {
241    (StatusCode::OK, [("x-foo", "bar")], "Hello, World!")
242}
243```
244
245However `impl IntoResponse` has a few limitations. Firstly it can only be used
246to return a single type:
247
248```rust,compile_fail
249use axum::{http::StatusCode, response::IntoResponse};
250
251async fn handler() -> impl IntoResponse {
252    if check_something() {
253        StatusCode::NOT_FOUND
254    } else {
255        "Hello, World!"
256    }
257}
258
259fn check_something() -> bool {
260    # false
261    // ...
262}
263```
264
265This function returns either a `StatusCode` or a `&'static str` which `impl
266Trait` doesn't allow.
267
268Secondly `impl IntoResponse` can lead to type inference issues when used with
269`Result` and `?`:
270
271```rust,compile_fail
272use axum::{http::StatusCode, response::IntoResponse};
273
274async fn handler() -> impl IntoResponse {
275    create_thing()?;
276    Ok(StatusCode::CREATED)
277}
278
279fn create_thing() -> Result<(), StatusCode> {
280    # Ok(())
281    // ...
282}
283```
284
285This is because `?` supports using the [`From`] trait to convert to a different
286error type but it doesn't know which type to convert to, because we only
287specified `impl IntoResponse` as the return type.
288
289`Result<impl IntoResponse, impl IntoResponse>` doesn't always work either:
290
291```rust,compile_fail
292use axum::{http::StatusCode, response::IntoResponse};
293
294async fn handler() -> Result<impl IntoResponse, impl IntoResponse> {
295    create_thing()?;
296    Ok(StatusCode::CREATED)
297}
298
299fn create_thing() -> Result<(), StatusCode> {
300    # Ok(())
301    // ...
302}
303```
304
305The solution is to use a concrete error type, such as `Result<impl IntoResponse, StatusCode>`:
306
307```rust
308use axum::{http::StatusCode, response::IntoResponse};
309
310async fn handler() -> Result<impl IntoResponse, StatusCode> {
311    create_thing()?;
312    Ok(StatusCode::CREATED)
313}
314
315fn create_thing() -> Result<(), StatusCode> {
316    # Ok(())
317    // ...
318}
319```
320
321Because of this it is generally not recommended to use `impl IntoResponse`
322unless you're familiar with the details of how `impl Trait` works.
323
324[`IntoResponse`]: crate::response::IntoResponse
325[`IntoResponseParts`]: crate::response::IntoResponseParts
326[`StatusCode`]: http::StatusCode
327