mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-07 00:00:12 +02:00
Accept S::Response: IntoResponse everywhere (#1165)
This commit is contained in:
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning].
|
|||||||
|
|
||||||
- **added:** Add `RouterExt::route_with_tsr` for adding routes with an
|
- **added:** Add `RouterExt::route_with_tsr` for adding routes with an
|
||||||
additional "trailing slash redirect" route ([#1119])
|
additional "trailing slash redirect" route ([#1119])
|
||||||
|
- **changed:** For methods that accept some `S: Service`, the bounds have been
|
||||||
|
relaxed so the response type must implement `IntoResponse` rather than being a
|
||||||
|
literal `Response`
|
||||||
|
|
||||||
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
http::Request,
|
http::Request,
|
||||||
response::{Redirect, Response},
|
response::{IntoResponse, Redirect},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use std::{convert::Infallible, future::ready};
|
use std::{convert::Infallible, future::ready};
|
||||||
@@ -161,7 +161,8 @@ pub trait RouterExt<B>: sealed::Sealed {
|
|||||||
/// ```
|
/// ```
|
||||||
fn route_with_tsr<T>(self, path: &str, service: T) -> Self
|
fn route_with_tsr<T>(self, path: &str, service: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
@@ -252,7 +253,8 @@ where
|
|||||||
|
|
||||||
fn route_with_tsr<T>(mut self, path: &str, service: T) -> Self
|
fn route_with_tsr<T>(mut self, path: &str, service: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use axum::{
|
|||||||
body::Body,
|
body::Body,
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
http::Request,
|
http::Request,
|
||||||
response::Response,
|
response::IntoResponse,
|
||||||
routing::{delete, get, on, post, MethodFilter},
|
routing::{delete, get, on, post, MethodFilter},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
@@ -141,7 +141,8 @@ where
|
|||||||
/// The routes will be nested at `/{resource_name}/:{resource_name}_id`.
|
/// The routes will be nested at `/{resource_name}/:{resource_name}_id`.
|
||||||
pub fn nest<T>(mut self, svc: T) -> Self
|
pub fn nest<T>(mut self, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
let path = self.show_update_destroy_path();
|
let path = self.show_update_destroy_path();
|
||||||
@@ -154,7 +155,8 @@ where
|
|||||||
/// The routes will be nested at `/{resource_name}`.
|
/// The routes will be nested at `/{resource_name}`.
|
||||||
pub fn nest_collection<T>(mut self, svc: T) -> Self
|
pub fn nest_collection<T>(mut self, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
let path = self.index_create_path();
|
let path = self.index_create_path();
|
||||||
@@ -172,7 +174,8 @@ where
|
|||||||
|
|
||||||
fn route<T>(mut self, path: &str, svc: T) -> Self
|
fn route<T>(mut self, path: &str, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
self.router = self.router.route(path, svc);
|
self.router = self.router.route(path, svc);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
body::{Body, HttpBody},
|
body::{Body, HttpBody},
|
||||||
error_handling::HandleError,
|
error_handling::HandleError,
|
||||||
response::Response,
|
response::IntoResponse,
|
||||||
routing::{get_service, Route},
|
routing::{get_service, Route},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
@@ -150,8 +150,8 @@ impl<B, T, F> SpaRouter<B, T, F> {
|
|||||||
impl<B, F, T> From<SpaRouter<B, T, F>> for Router<B>
|
impl<B, F, T> From<SpaRouter<B, T, F>> for Router<B>
|
||||||
where
|
where
|
||||||
F: Clone + Send + 'static,
|
F: Clone + Send + 'static,
|
||||||
HandleError<Route<B, io::Error>, F, T>:
|
HandleError<Route<B, io::Error>, F, T>: Service<Request<B>, Error = Infallible>,
|
||||||
Service<Request<B>, Response = Response, Error = Infallible>,
|
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Response: IntoResponse + Send,
|
||||||
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Future: Send,
|
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Future: Send,
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- **added:** Support any middleware response that implements `IntoResponse` ([#1152])
|
- **added:** Support any middleware response that implements `IntoResponse` ([#1152])
|
||||||
- **breaking:** Require middleware added with `Handler::layer` to have
|
- **breaking:** Require middleware added with `Handler::layer` to have
|
||||||
`Infallible` as the error type ([#1152])
|
`Infallible` as the error type ([#1152])
|
||||||
|
- **changed:** For methods that accept some `S: Service`, the bounds have been
|
||||||
|
relaxed so the response type must implement `IntoResponse` rather than being a
|
||||||
|
literal `Response`
|
||||||
|
|
||||||
[#1171]: https://github.com/tokio-rs/axum/pull/1171
|
[#1171]: https://github.com/tokio-rs/axum/pull/1171
|
||||||
[#1077]: https://github.com/tokio-rs/axum/pull/1077
|
[#1077]: https://github.com/tokio-rs/axum/pull/1077
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#![doc = include_str!("../docs/error_handling.md")]
|
#![doc = include_str!("../docs/error_handling.md")]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{boxed, Bytes, HttpBody},
|
body::boxed,
|
||||||
extract::{FromRequest, RequestParts},
|
extract::{FromRequest, RequestParts},
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
BoxError,
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
@@ -114,17 +113,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F, ReqBody, ResBody, Fut, Res> Service<Request<ReqBody>> for HandleError<S, F, ()>
|
impl<S, F, ReqBody, Fut, Res> Service<Request<ReqBody>> for HandleError<S, F, ()>
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + Send,
|
||||||
S::Error: Send,
|
S::Error: Send,
|
||||||
S::Future: Send,
|
S::Future: Send,
|
||||||
F: FnOnce(S::Error) -> Fut + Clone + Send + 'static,
|
F: FnOnce(S::Error) -> Fut + Clone + Send + 'static,
|
||||||
Fut: Future<Output = Res> + Send,
|
Fut: Future<Output = Res> + Send,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
ReqBody: Send + 'static,
|
ReqBody: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
@@ -142,7 +140,7 @@ where
|
|||||||
|
|
||||||
let future = Box::pin(async move {
|
let future = Box::pin(async move {
|
||||||
match inner.oneshot(req).await {
|
match inner.oneshot(req).await {
|
||||||
Ok(res) => Ok(res.map(boxed)),
|
Ok(res) => Ok(res.into_response()),
|
||||||
Err(err) => Ok(f(err).await.into_response()),
|
Err(err) => Ok(f(err).await.into_response()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -154,10 +152,11 @@ where
|
|||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! impl_service {
|
macro_rules! impl_service {
|
||||||
( $($ty:ident),* $(,)? ) => {
|
( $($ty:ident),* $(,)? ) => {
|
||||||
impl<S, F, ReqBody, ResBody, Res, Fut, $($ty,)*> Service<Request<ReqBody>>
|
impl<S, F, ReqBody, Res, Fut, $($ty,)*> Service<Request<ReqBody>>
|
||||||
for HandleError<S, F, ($($ty,)*)>
|
for HandleError<S, F, ($($ty,)*)>
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + Send,
|
||||||
S::Error: Send,
|
S::Error: Send,
|
||||||
S::Future: Send,
|
S::Future: Send,
|
||||||
F: FnOnce($($ty),*, S::Error) -> Fut + Clone + Send + 'static,
|
F: FnOnce($($ty),*, S::Error) -> Fut + Clone + Send + 'static,
|
||||||
@@ -165,8 +164,6 @@ macro_rules! impl_service {
|
|||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
$( $ty: FromRequest<ReqBody> + Send,)*
|
$( $ty: FromRequest<ReqBody> + Send,)*
|
||||||
ReqBody: Send + 'static,
|
ReqBody: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
@@ -202,7 +199,7 @@ macro_rules! impl_service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match inner.oneshot(req).await {
|
match inner.oneshot(req).await {
|
||||||
Ok(res) => Ok(res.map(boxed)),
|
Ok(res) => Ok(res.into_response()),
|
||||||
Err(err) => Ok(f($($ty),*, err).await.into_response().map(boxed)),
|
Err(err) => Ok(f($($ty),*, err).await.into_response().map(boxed)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
body::{Bytes, HttpBody},
|
|
||||||
extract::{FromRequest, RequestParts},
|
extract::{FromRequest, RequestParts},
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
BoxError,
|
|
||||||
};
|
};
|
||||||
use futures_util::{future::BoxFuture, ready};
|
use futures_util::{future::BoxFuture, ready};
|
||||||
use http::Request;
|
use http::Request;
|
||||||
@@ -90,6 +88,8 @@ use tower_service::Service;
|
|||||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`Bytes`]: bytes::Bytes
|
||||||
pub fn from_extractor<E>() -> FromExtractorLayer<E> {
|
pub fn from_extractor<E>() -> FromExtractorLayer<E> {
|
||||||
FromExtractorLayer(PhantomData)
|
FromExtractorLayer(PhantomData)
|
||||||
}
|
}
|
||||||
@@ -166,13 +166,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E, ReqBody, ResBody> Service<Request<ReqBody>> for FromExtractor<S, E>
|
impl<S, E, ReqBody> Service<Request<ReqBody>> for FromExtractor<S, E>
|
||||||
where
|
where
|
||||||
E: FromRequest<ReqBody> + 'static,
|
E: FromRequest<ReqBody> + 'static,
|
||||||
ReqBody: Default + Send + 'static,
|
ReqBody: Default + Send + 'static,
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
S: Service<Request<ReqBody>> + Clone,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
S::Response: IntoResponse,
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = S::Error;
|
type Error = S::Error;
|
||||||
@@ -225,13 +224,12 @@ pin_project! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ReqBody, S, E, ResBody> Future for ResponseFuture<ReqBody, S, E>
|
impl<ReqBody, S, E> Future for ResponseFuture<ReqBody, S, E>
|
||||||
where
|
where
|
||||||
E: FromRequest<ReqBody>,
|
E: FromRequest<ReqBody>,
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
S: Service<Request<ReqBody>>,
|
||||||
|
S::Response: IntoResponse,
|
||||||
ReqBody: Default,
|
ReqBody: Default,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
type Output = Result<Response, S::Error>;
|
type Output = Result<Response, S::Error>;
|
||||||
|
|
||||||
@@ -259,7 +257,7 @@ where
|
|||||||
StateProj::Call { future } => {
|
StateProj::Call { future } => {
|
||||||
return future
|
return future
|
||||||
.poll(cx)
|
.poll(cx)
|
||||||
.map(|result| result.map(|response| response.map(crate::body::boxed)));
|
.map(|result| result.map(IntoResponse::into_response));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use crate::{
|
use crate::response::{IntoResponse, Response};
|
||||||
body::{self, Bytes, HttpBody},
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
BoxError,
|
|
||||||
};
|
|
||||||
use axum_core::extract::{FromRequest, RequestParts};
|
use axum_core::extract::{FromRequest, RequestParts};
|
||||||
use futures_util::future::BoxFuture;
|
use futures_util::future::BoxFuture;
|
||||||
use http::Request;
|
use http::Request;
|
||||||
@@ -16,7 +12,6 @@ use std::{
|
|||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tower::{util::BoxCloneService, ServiceBuilder};
|
use tower::{util::BoxCloneService, ServiceBuilder};
|
||||||
use tower_http::ServiceBuilderExt;
|
|
||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
@@ -256,20 +251,19 @@ where
|
|||||||
macro_rules! impl_service {
|
macro_rules! impl_service {
|
||||||
( $($ty:ident),* $(,)? ) => {
|
( $($ty:ident),* $(,)? ) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<F, Fut, Out, S, ReqBody, ResBody, $($ty,)*> Service<Request<ReqBody>> for FromFn<F, S, ($($ty,)*)>
|
impl<F, Fut, Out, S, ReqBody, $($ty,)*> Service<Request<ReqBody>> for FromFn<F, S, ($($ty,)*)>
|
||||||
where
|
where
|
||||||
F: FnMut($($ty),*, Next<ReqBody>) -> Fut + Clone + Send + 'static,
|
F: FnMut($($ty),*, Next<ReqBody>) -> Fut + Clone + Send + 'static,
|
||||||
$( $ty: FromRequest<ReqBody> + Send, )*
|
$( $ty: FromRequest<ReqBody> + Send, )*
|
||||||
Fut: Future<Output = Out> + Send + 'static,
|
Fut: Future<Output = Out> + Send + 'static,
|
||||||
Out: IntoResponse + 'static,
|
Out: IntoResponse + 'static,
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible>
|
S: Service<Request<ReqBody>, Error = Infallible>
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
S::Response: IntoResponse,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ReqBody: Send + 'static,
|
ReqBody: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
type Response = Response;
|
type Response = Response;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
@@ -296,7 +290,7 @@ macro_rules! impl_service {
|
|||||||
|
|
||||||
let inner = ServiceBuilder::new()
|
let inner = ServiceBuilder::new()
|
||||||
.boxed_clone()
|
.boxed_clone()
|
||||||
.map_response_body(body::boxed)
|
.map_response(IntoResponse::into_response)
|
||||||
.service(ready_inner);
|
.service(ready_inner);
|
||||||
let next = Next { inner };
|
let next = Next { inner };
|
||||||
|
|
||||||
@@ -370,7 +364,7 @@ impl fmt::Debug for ResponseFuture {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{body::Empty, routing::get, Router};
|
use crate::{body::Body, routing::get, Router};
|
||||||
use http::{HeaderMap, StatusCode};
|
use http::{HeaderMap, StatusCode};
|
||||||
use tower::ServiceExt;
|
use tower::ServiceExt;
|
||||||
|
|
||||||
@@ -392,12 +386,7 @@ mod tests {
|
|||||||
.layer(from_fn(insert_header));
|
.layer(from_fn(insert_header));
|
||||||
|
|
||||||
let res = app
|
let res = app
|
||||||
.oneshot(
|
.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
|
||||||
Request::builder()
|
|
||||||
.uri("/")
|
|
||||||
.body(body::boxed(Empty::new()))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::{
|
|||||||
http::{Method, Request, StatusCode},
|
http::{Method, Request, StatusCode},
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::{future::RouteFuture, Fallback, MethodFilter, Route},
|
routing::{future::RouteFuture, Fallback, MethodFilter, Route},
|
||||||
BoxError,
|
|
||||||
};
|
};
|
||||||
use axum_core::response::IntoResponse;
|
use axum_core::response::IntoResponse;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
@@ -17,7 +16,7 @@ use std::{
|
|||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tower::{service_fn, util::MapResponseLayer, ServiceBuilder, ServiceExt};
|
use tower::{service_fn, util::MapResponseLayer, ServiceBuilder};
|
||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
@@ -76,12 +75,11 @@ macro_rules! top_level_service_fn {
|
|||||||
$name:ident, $method:ident
|
$name:ident, $method:ident
|
||||||
) => {
|
) => {
|
||||||
$(#[$m])+
|
$(#[$m])+
|
||||||
pub fn $name<S, ReqBody, ResBody>(svc: S) -> MethodRouter<ReqBody, S::Error>
|
pub fn $name<S, ReqBody>(svc: S) -> MethodRouter<ReqBody, S::Error>
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
on_service(MethodFilter::$method, svc)
|
on_service(MethodFilter::$method, svc)
|
||||||
}
|
}
|
||||||
@@ -208,15 +206,14 @@ macro_rules! chained_service_fn {
|
|||||||
$name:ident, $method:ident
|
$name:ident, $method:ident
|
||||||
) => {
|
) => {
|
||||||
$(#[$m])+
|
$(#[$m])+
|
||||||
pub fn $name<S, ResBody>(self, svc: S) -> Self
|
pub fn $name<S>(self, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = E>
|
S: Service<Request<ReqBody>, Error = E>
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
self.on_service(MethodFilter::$method, svc)
|
self.on_service(MethodFilter::$method, svc)
|
||||||
}
|
}
|
||||||
@@ -316,15 +313,11 @@ top_level_service_fn!(trace_service, TRACE);
|
|||||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on_service<S, ReqBody, ResBody>(
|
pub fn on_service<S, ReqBody>(filter: MethodFilter, svc: S) -> MethodRouter<ReqBody, S::Error>
|
||||||
filter: MethodFilter,
|
|
||||||
svc: S,
|
|
||||||
) -> MethodRouter<ReqBody, S::Error>
|
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
MethodRouter::new().on_service(filter, svc)
|
MethodRouter::new().on_service(filter, svc)
|
||||||
}
|
}
|
||||||
@@ -382,12 +375,11 @@ where
|
|||||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn any_service<S, ReqBody, ResBody>(svc: S) -> MethodRouter<ReqBody, S::Error>
|
pub fn any_service<S, ReqBody>(svc: S) -> MethodRouter<ReqBody, S::Error>
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
MethodRouter::new().fallback(svc).skip_allow_header()
|
MethodRouter::new().fallback(svc).skip_allow_header()
|
||||||
}
|
}
|
||||||
@@ -684,17 +676,13 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
|
|||||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on_service<S, ResBody>(self, filter: MethodFilter, svc: S) -> Self
|
pub fn on_service<S>(self, filter: MethodFilter, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = E>
|
S: Service<Request<ReqBody>, Error = E> + Clone + Send + 'static,
|
||||||
+ Clone
|
S::Response: IntoResponse + 'static,
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
self.on_service_boxed_response_body(filter, svc.map_response(|res| res.map(boxed)))
|
self.on_service_boxed_response_body(filter, svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
chained_service_fn!(delete_service, DELETE);
|
chained_service_fn!(delete_service, DELETE);
|
||||||
@@ -707,23 +695,20 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
|
|||||||
chained_service_fn!(trace_service, TRACE);
|
chained_service_fn!(trace_service, TRACE);
|
||||||
|
|
||||||
#[doc = include_str!("../docs/method_routing/fallback.md")]
|
#[doc = include_str!("../docs/method_routing/fallback.md")]
|
||||||
pub fn fallback<S, ResBody>(mut self, svc: S) -> Self
|
pub fn fallback<S>(mut self, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = E>
|
S: Service<Request<ReqBody>, Error = E> + Clone + Send + 'static,
|
||||||
+ Clone
|
S::Response: IntoResponse + 'static,
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
|
||||||
ResBody::Error: Into<BoxError>,
|
|
||||||
{
|
{
|
||||||
self.fallback = Fallback::Custom(Route::new(svc.map_response(|res| res.map(boxed))));
|
self.fallback = Fallback::Custom(Route::new(svc));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fallback_boxed_response_body<S>(mut self, svc: S) -> Self
|
fn fallback_boxed_response_body<S>(mut self, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response, Error = E> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>, Error = E> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
self.fallback = Fallback::Custom(Route::new(svc));
|
self.fallback = Fallback::Custom(Route::new(svc));
|
||||||
@@ -886,9 +871,10 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
|
|||||||
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<ReqBody, Infallible>
|
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<ReqBody, Infallible>
|
||||||
where
|
where
|
||||||
F: Clone + Send + 'static,
|
F: Clone + Send + 'static,
|
||||||
HandleError<Route<ReqBody, E>, F, T>:
|
HandleError<Route<ReqBody, E>, F, T>: Service<Request<ReqBody>, Error = Infallible>,
|
||||||
Service<Request<ReqBody>, Response = Response, Error = Infallible>,
|
|
||||||
<HandleError<Route<ReqBody, E>, F, T> as Service<Request<ReqBody>>>::Future: Send,
|
<HandleError<Route<ReqBody, E>, F, T> as Service<Request<ReqBody>>>::Future: Send,
|
||||||
|
<HandleError<Route<ReqBody, E>, F, T> as Service<Request<ReqBody>>>::Response:
|
||||||
|
IntoResponse + Send,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
ReqBody: 'static,
|
ReqBody: 'static,
|
||||||
@@ -898,7 +884,8 @@ impl<ReqBody, E> MethodRouter<ReqBody, E> {
|
|||||||
|
|
||||||
fn on_service_boxed_response_body<S>(self, filter: MethodFilter, svc: S) -> Self
|
fn on_service_boxed_response_body<S>(self, filter: MethodFilter, svc: S) -> Self
|
||||||
where
|
where
|
||||||
S: Service<Request<ReqBody>, Response = Response, Error = E> + Clone + Send + 'static,
|
S: Service<Request<ReqBody>, Error = E> + Clone + Send + 'static,
|
||||||
|
S::Response: IntoResponse + 'static,
|
||||||
S::Future: Send + 'static,
|
S::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
macro_rules! set_service {
|
macro_rules! set_service {
|
||||||
@@ -1319,14 +1306,22 @@ mod tests {
|
|||||||
|
|
||||||
async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String)
|
async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String)
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response, Error = Infallible>,
|
S: Service<Request<Body>, Error = Infallible>,
|
||||||
|
S::Response: IntoResponse,
|
||||||
{
|
{
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.uri("/")
|
.uri("/")
|
||||||
.method(method)
|
.method(method)
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let response = svc.ready().await.unwrap().call(request).await.unwrap();
|
let response = svc
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.call(request)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.into_response();
|
||||||
let (parts, body) = response.into_parts();
|
let (parts, body) = response.into_parts();
|
||||||
let body = String::from_utf8(hyper::body::to_bytes(body).await.unwrap().to_vec()).unwrap();
|
let body = String::from_utf8(hyper::body::to_bytes(body).await.unwrap().to_vec()).unwrap();
|
||||||
(parts.status, parts.headers, body)
|
(parts.status, parts.headers, body)
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ where
|
|||||||
#[doc = include_str!("../docs/routing/route.md")]
|
#[doc = include_str!("../docs/routing/route.md")]
|
||||||
pub fn route<T>(mut self, path: &str, service: T) -> Self
|
pub fn route<T>(mut self, path: &str, service: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
@@ -176,7 +177,8 @@ where
|
|||||||
#[doc = include_str!("../docs/routing/nest.md")]
|
#[doc = include_str!("../docs/routing/nest.md")]
|
||||||
pub fn nest<T>(mut self, mut path: &str, svc: T) -> Self
|
pub fn nest<T>(mut self, mut path: &str, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
@@ -368,7 +370,8 @@ where
|
|||||||
#[doc = include_str!("../docs/routing/fallback.md")]
|
#[doc = include_str!("../docs/routing/fallback.md")]
|
||||||
pub fn fallback<T>(mut self, svc: T) -> Self
|
pub fn fallback<T>(mut self, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
self.fallback = Fallback::Custom(Route::new(svc));
|
self.fallback = Fallback::Custom(Route::new(svc));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
body::{boxed, Body, Empty, HttpBody},
|
body::{boxed, Body, Empty, HttpBody},
|
||||||
response::Response,
|
response::Response,
|
||||||
};
|
};
|
||||||
|
use axum_core::response::IntoResponse;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use http::{
|
use http::{
|
||||||
header::{self, CONTENT_LENGTH},
|
header::{self, CONTENT_LENGTH},
|
||||||
@@ -30,10 +31,13 @@ pub struct Route<B = Body, E = Infallible>(BoxCloneService<Request<B>, Response,
|
|||||||
impl<B, E> Route<B, E> {
|
impl<B, E> Route<B, E> {
|
||||||
pub(super) fn new<T>(svc: T) -> Self
|
pub(super) fn new<T>(svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = E> + Clone + Send + 'static,
|
T: Service<Request<B>, Error = E> + Clone + Send + 'static,
|
||||||
|
T::Response: IntoResponse + 'static,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
Self(BoxCloneService::new(svc))
|
Self(BoxCloneService::new(
|
||||||
|
svc.map_response(IntoResponse::into_response),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn oneshot_inner(
|
pub(crate) fn oneshot_inner(
|
||||||
|
|||||||
Reference in New Issue
Block a user