2021-06-07 16:28:40 +02:00
|
|
|
//! Types and traits for generating responses.
|
|
|
|
|
|
2021-05-31 22:54:21 +02:00
|
|
|
use crate::Body;
|
2021-05-30 13:24:03 +02:00
|
|
|
use bytes::Bytes;
|
2021-06-01 08:32:58 +02:00
|
|
|
use http::{header, HeaderMap, HeaderValue, Response, StatusCode};
|
2021-05-30 13:24:03 +02:00
|
|
|
use serde::Serialize;
|
2021-06-06 15:19:54 +02:00
|
|
|
use std::{borrow::Cow, convert::Infallible};
|
2021-06-01 08:32:58 +02:00
|
|
|
use tower::util::Either;
|
2021-05-30 13:24:03 +02:00
|
|
|
|
2021-06-06 23:58:44 +02:00
|
|
|
/// Trait for generating responses.
|
|
|
|
|
///
|
|
|
|
|
/// Types that implement `IntoResponse` can be returned from handlers.
|
2021-06-06 22:41:52 +02:00
|
|
|
pub trait IntoResponse {
|
2021-06-06 23:58:44 +02:00
|
|
|
/// Create a response.
|
2021-06-06 22:41:52 +02:00
|
|
|
fn into_response(self) -> Response<Body>;
|
2021-05-31 22:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for () {
|
2021-06-06 15:19:54 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
|
|
|
|
Response::new(Body::empty())
|
2021-05-31 22:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for Infallible {
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-31 22:54:21 +02:00
|
|
|
match self {}
|
|
|
|
|
}
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T, K> IntoResponse for Either<T, K>
|
2021-05-31 20:42:57 +02:00
|
|
|
where
|
2021-06-06 22:41:52 +02:00
|
|
|
T: IntoResponse,
|
|
|
|
|
K: IntoResponse,
|
2021-05-31 20:42:57 +02:00
|
|
|
{
|
2021-06-06 22:41:52 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-31 22:54:21 +02:00
|
|
|
match self {
|
|
|
|
|
Either::A(inner) => inner.into_response(),
|
|
|
|
|
Either::B(inner) => inner.into_response(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T, E> IntoResponse for Result<T, E>
|
2021-05-31 22:54:21 +02:00
|
|
|
where
|
2021-06-06 22:41:52 +02:00
|
|
|
T: IntoResponse,
|
|
|
|
|
E: IntoResponse,
|
2021-05-31 22:54:21 +02:00
|
|
|
{
|
2021-06-06 22:41:52 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-31 22:54:21 +02:00
|
|
|
match self {
|
|
|
|
|
Ok(value) => value.into_response(),
|
|
|
|
|
Err(err) => err.into_response(),
|
|
|
|
|
}
|
2021-05-31 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for Response<Body> {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Self {
|
|
|
|
|
self
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-22 21:22:46 +02:00
|
|
|
impl IntoResponse for Body {
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
|
|
|
|
Response::new(self)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for &'static str {
|
2021-06-06 15:19:54 +02:00
|
|
|
#[inline]
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-06-06 15:19:54 +02:00
|
|
|
Cow::Borrowed(self).into_response()
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for String {
|
2021-06-06 15:19:54 +02:00
|
|
|
#[inline]
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-06-06 15:19:54 +02:00
|
|
|
Cow::<'static, str>::Owned(self).into_response()
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for std::borrow::Cow<'static, str> {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-06-06 15:19:54 +02:00
|
|
|
let mut res = Response::new(Body::from(self));
|
|
|
|
|
res.headers_mut()
|
|
|
|
|
.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain"));
|
|
|
|
|
res
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for Bytes {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-30 14:33:20 +02:00
|
|
|
let mut res = Response::new(Body::from(self));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static("application/octet-stream"),
|
|
|
|
|
);
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for &'static [u8] {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-30 14:33:20 +02:00
|
|
|
let mut res = Response::new(Body::from(self));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static("application/octet-stream"),
|
|
|
|
|
);
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for Vec<u8> {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-30 14:33:20 +02:00
|
|
|
let mut res = Response::new(Body::from(self));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static("application/octet-stream"),
|
|
|
|
|
);
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for std::borrow::Cow<'static, [u8]> {
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-05-30 14:33:20 +02:00
|
|
|
let mut res = Response::new(Body::from(self));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static("application/octet-stream"),
|
|
|
|
|
);
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl IntoResponse for StatusCode {
|
2021-06-06 15:19:54 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
|
|
|
|
Response::builder()
|
|
|
|
|
.status(self)
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap()
|
2021-06-06 11:37:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-30 13:24:03 +02:00
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T> IntoResponse for (StatusCode, T)
|
2021-05-30 13:24:03 +02:00
|
|
|
where
|
2021-07-22 11:14:55 +02:00
|
|
|
T: IntoResponse,
|
2021-05-30 13:24:03 +02:00
|
|
|
{
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-07-22 11:14:55 +02:00
|
|
|
let mut res = self.1.into_response();
|
|
|
|
|
*res.status_mut() = self.0;
|
|
|
|
|
res
|
2021-06-06 11:37:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-31 22:54:21 +02:00
|
|
|
|
2021-06-12 20:50:30 +02:00
|
|
|
impl<T> IntoResponse for (HeaderMap, T)
|
|
|
|
|
where
|
2021-07-22 11:14:55 +02:00
|
|
|
T: IntoResponse,
|
2021-06-12 20:50:30 +02:00
|
|
|
{
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-07-22 11:14:55 +02:00
|
|
|
let mut res = self.1.into_response();
|
2021-08-06 16:31:38 +08:00
|
|
|
res.headers_mut().extend(self.0);
|
2021-06-12 20:50:30 +02:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T> IntoResponse for (StatusCode, HeaderMap, T)
|
2021-06-06 11:37:08 +02:00
|
|
|
where
|
2021-07-22 11:14:55 +02:00
|
|
|
T: IntoResponse,
|
2021-06-06 11:37:08 +02:00
|
|
|
{
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-07-22 11:14:55 +02:00
|
|
|
let mut res = self.2.into_response();
|
2021-06-06 11:37:08 +02:00
|
|
|
*res.status_mut() = self.0;
|
2021-08-06 16:31:38 +08:00
|
|
|
res.headers_mut().extend(self.1);
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-30 14:33:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-30 13:24:03 +02:00
|
|
|
|
2021-07-22 21:21:53 +02:00
|
|
|
impl IntoResponse for HeaderMap {
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
|
|
|
|
let mut res = Response::new(Body::empty());
|
|
|
|
|
*res.headers_mut() = self;
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:58:44 +02:00
|
|
|
/// An HTML response.
|
|
|
|
|
///
|
|
|
|
|
/// Will automatically get `Content-Type: text/html`.
|
2021-06-07 15:45:19 +02:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2021-05-31 10:20:07 +02:00
|
|
|
pub struct Html<T>(pub T);
|
|
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T> IntoResponse for Html<T>
|
2021-05-31 10:20:07 +02:00
|
|
|
where
|
2021-06-06 11:37:08 +02:00
|
|
|
T: Into<Body>,
|
2021-05-31 10:20:07 +02:00
|
|
|
{
|
2021-05-31 22:54:21 +02:00
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-06-06 11:37:08 +02:00
|
|
|
let mut res = Response::new(self.0.into());
|
2021-05-31 10:20:07 +02:00
|
|
|
res.headers_mut()
|
|
|
|
|
.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html"));
|
2021-05-31 22:54:21 +02:00
|
|
|
res
|
2021-05-31 10:20:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:34:42 +02:00
|
|
|
impl<T> From<T> for Html<T> {
|
|
|
|
|
fn from(inner: T) -> Self {
|
|
|
|
|
Self(inner)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:58:44 +02:00
|
|
|
/// A JSON response.
|
|
|
|
|
///
|
|
|
|
|
/// Can be created from any type that implements [`serde::Serialize`].
|
|
|
|
|
///
|
|
|
|
|
/// Will automatically get `Content-Type: application/json`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use serde_json::json;
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{body::Body, response::{Json, IntoResponse}};
|
2021-06-06 23:58:44 +02:00
|
|
|
/// use http::{Response, header::CONTENT_TYPE};
|
|
|
|
|
///
|
|
|
|
|
/// let json = json!({
|
|
|
|
|
/// "data": 42,
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// let response: Response<Body> = Json(json).into_response();
|
|
|
|
|
///
|
|
|
|
|
/// assert_eq!(
|
|
|
|
|
/// response.headers().get(CONTENT_TYPE).unwrap(),
|
|
|
|
|
/// "application/json",
|
|
|
|
|
/// );
|
|
|
|
|
/// ```
|
2021-06-07 15:45:19 +02:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2021-06-06 11:37:08 +02:00
|
|
|
pub struct Json<T>(pub T);
|
2021-06-01 00:34:09 +02:00
|
|
|
|
2021-06-06 22:41:52 +02:00
|
|
|
impl<T> IntoResponse for Json<T>
|
2021-06-01 00:34:09 +02:00
|
|
|
where
|
2021-06-06 11:37:08 +02:00
|
|
|
T: Serialize,
|
2021-06-01 00:34:09 +02:00
|
|
|
{
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
2021-06-06 11:37:08 +02:00
|
|
|
let bytes = match serde_json::to_vec(&self.0) {
|
|
|
|
|
Ok(res) => res,
|
|
|
|
|
Err(err) => {
|
|
|
|
|
return Response::builder()
|
2021-07-22 13:26:14 +02:00
|
|
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
2021-06-06 11:37:08 +02:00
|
|
|
.header(header::CONTENT_TYPE, "text/plain")
|
|
|
|
|
.body(Body::from(err.to_string()))
|
|
|
|
|
.unwrap();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut res = Response::new(Body::from(bytes));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static("application/json"),
|
|
|
|
|
);
|
|
|
|
|
res
|
2021-06-01 00:34:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-19 12:34:42 +02:00
|
|
|
|
|
|
|
|
impl<T> From<T> for Json<T> {
|
|
|
|
|
fn from(inner: T) -> Self {
|
|
|
|
|
Self(inner)
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-06 16:31:38 +08:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use http::header::{HeaderMap, HeaderName};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_merge_headers() {
|
|
|
|
|
struct MyResponse;
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for MyResponse {
|
|
|
|
|
fn into_response(self) -> Response<Body> {
|
|
|
|
|
let mut resp = Response::new(String::new().into());
|
|
|
|
|
resp.headers_mut()
|
|
|
|
|
.insert(HeaderName::from_static("a"), HeaderValue::from_static("1"));
|
|
|
|
|
resp
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn check(resp: impl IntoResponse) {
|
|
|
|
|
let resp = resp.into_response();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
resp.headers().get(HeaderName::from_static("a")).unwrap(),
|
|
|
|
|
&HeaderValue::from_static("1")
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
resp.headers().get(HeaderName::from_static("b")).unwrap(),
|
|
|
|
|
&HeaderValue::from_static("2")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let headers: HeaderMap =
|
|
|
|
|
std::iter::once((HeaderName::from_static("b"), HeaderValue::from_static("2")))
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
check((headers.clone(), MyResponse));
|
|
|
|
|
check((StatusCode::OK, headers, MyResponse));
|
|
|
|
|
}
|
|
|
|
|
}
|