pavex/response/
into_response.rs

1use bytes::Bytes;
2use http::StatusCode;
3use http_body_util::Empty;
4
5// Most of this module is an adaptation of the corresponding
6// module in `axum-core`
7//
8// Copyright (c) 2019 Axum Contributors
9//
10// Permission is hereby granted, free of charge, to any
11// person obtaining a copy of this software and associated
12// documentation files (the "Software"), to deal in the
13// Software without restriction, including without
14// limitation the rights to use, copy, modify, merge,
15// publish, distribute, sublicense, and/or sell copies of
16// the Software, and to permit persons to whom the Software
17// is furnished to do so, subject to the following
18// conditions:
19//
20// The above copyright notice and this permission notice
21// shall be included in all copies or substantial portions
22// of the Software.
23//
24// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
25// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
26// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
27// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
28// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
29// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
31// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32// DEALINGS IN THE SOFTWARE.
33use crate::{
34    Response,
35    response::{ResponseBody, ResponseHead},
36};
37
38/// Convert a type into a [`Response`].
39///
40/// Types that implement `IntoResponse` can be returned:
41///
42/// - as the output type of an infallible route handler,
43///   e.g. `fn handler() -> T` where `T: IntoResponse`.
44/// - as the `Ok` variant of the `Result` returned by a fallible route handler,
45///   e.g. `fn handler() -> Result<T, E>` where `T: IntoResponse`.
46//
47// # Implementation notes
48//
49// This is our primary divergence from `axum-core`'s API: we do NOT implement
50// `IntoResponse` for `Result<T, E>` if `T: IntoResponse` and `E: IntoResponse`.
51// It would create ambiguity: how should I handle errors? Do I need to implement
52// `IntoResponse` for `E`? Do I need to specify an error handler in the blueprint?
53// What if I do both, what gets invoked?
54//
55// ## Other divergences
56//
57// We are more conservative in the range of types that we implement `IntoResponse` for.
58// In particular, no tuples, no `()`, no types for which we'd have to infer a status code.
59pub trait IntoResponse {
60    /// Convert `self` into an HTTP response.
61    fn into_response(self) -> Response;
62}
63
64impl<B> IntoResponse for http::Response<B>
65where
66    B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
67    B::Error: Into<Box<dyn std::error::Error + Send + Sync>> + 'static,
68{
69    fn into_response(self) -> Response {
70        let r: Response = self.into();
71        r.into_response()
72    }
73}
74
75impl IntoResponse for Response {
76    fn into_response(self) -> Response {
77        self
78    }
79}
80
81impl IntoResponse for StatusCode {
82    fn into_response(self) -> Response {
83        Response::new(self)
84    }
85}
86
87impl IntoResponse for http::response::Parts {
88    fn into_response(self) -> Response {
89        http::Response::from_parts(self, ResponseBody::new(Empty::new())).into()
90    }
91}
92
93impl IntoResponse for ResponseHead {
94    fn into_response(self) -> Response {
95        Response::from_parts(self, ResponseBody::default())
96    }
97}