Remove tower from axum's public API (#229)

Instead rely on `tower-service` and `tower-layer`. `tower` itself is
only used internally.

Fixes https://github.com/tokio-rs/axum/issues/186
This commit is contained in:
David Pedersen 2021-08-21 15:01:30 +02:00 committed by GitHub
parent 35ea7ca0ff
commit f8a0d81d79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 102 additions and 50 deletions

View file

@ -47,6 +47,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Convert `RequestAlreadyExtracted` to an enum with each possible error variant ([#167](https://github.com/tokio-rs/axum/pull/167))
- `Router::check_infallible` now returns a `CheckInfallible` service. This
is to improve compile times.
- `Router::into_make_service` now returns `routing::IntoMakeService` rather than
`tower::make::Shared` ([#229](https://github.com/tokio-rs/axum/pull/229))
- All usage of `tower::BoxError` has been replaced with `axum::BoxError` ([#229](https://github.com/tokio-rs/axum/pull/229))
- `tower::util::Either` no longer implements `IntoResponse` ([#229](https://github.com/tokio-rs/axum/pull/229))
- These future types have been moved
- `extract::extractor_middleware::ExtractorMiddlewareResponseFuture` moved
to `extract::extractor_middleware::future::ResponseFuture` ([#133](https://github.com/tokio-rs/axum/pull/133))

View file

@ -36,6 +36,8 @@ serde_urlencoded = "0.7"
tokio = { version = "1", features = ["time"] }
tokio-util = "0.6"
tower = { version = "0.4", default-features = false, features = ["util", "buffer", "make"] }
tower-service = "0.3"
tower-layer = "0.3"
tower-http = { version = "0.1", features = ["add-extension", "map-response-body"] }
sync_wrapper = "0.1.1"
@ -56,6 +58,7 @@ uuid = { version = "0.8", features = ["serde", "v4"] }
tokio-stream = "0.1"
[dev-dependencies.tower]
package = "tower"
version = "0.4"
features = [
"util",

View file

@ -1,7 +1,7 @@
//! HTTP body utilities.
use crate::BoxError;
use crate::Error;
use tower::BoxError;
#[doc(no_inline)]
pub use http_body::{Body as HttpBody, Empty, Full};

View file

@ -8,7 +8,8 @@ use std::{
};
use tokio::sync::{mpsc, oneshot, OwnedSemaphorePermit, Semaphore};
use tokio_util::sync::PollSemaphore;
use tower::{Service, ServiceExt};
use tower::ServiceExt;
use tower_service::Service;
/// A version of [`tower::buffer::Buffer`] which panicks on channel related errors, thus keeping
/// the error type of the service.

View file

@ -1,5 +1,5 @@
use crate::BoxError;
use std::{error::Error as StdError, fmt};
use tower::BoxError;
/// Errors that can happen when using axum.
#[derive(Debug)]

View file

@ -14,8 +14,8 @@ use std::{
net::SocketAddr,
task::{Context, Poll},
};
use tower::Service;
use tower_http::add_extension::AddExtension;
use tower_service::Service;
/// A [`MakeService`] created from a router.
///

View file

@ -3,6 +3,7 @@
//! See [`extractor_middleware`] for more details.
use super::{FromRequest, RequestParts};
use crate::BoxError;
use crate::{body::BoxBody, response::IntoResponse};
use bytes::Bytes;
use futures_util::{future::BoxFuture, ready};
@ -15,7 +16,8 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::{BoxError, Layer, Service};
use tower_layer::Layer;
use tower_service::Service;
/// Convert an extractor into a middleware.
///

View file

@ -1,10 +1,10 @@
use super::{has_content_type, rejection::*, take_body, FromRequest, RequestParts};
use crate::BoxError;
use async_trait::async_trait;
use bytes::Buf;
use http::Method;
use serde::de::DeserializeOwned;
use std::ops::Deref;
use tower::BoxError;
/// Extractor that deserializes `application/x-www-form-urlencoded` requests
/// into some type.

View file

@ -3,6 +3,7 @@
//! See [`Multipart`] for more details.
use super::{rejection::*, BodyStream, FromRequest, RequestParts};
use crate::BoxError;
use async_trait::async_trait;
use bytes::Bytes;
use futures_util::stream::Stream;
@ -13,7 +14,6 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::BoxError;
/// Extractor that parses `multipart/form-data` requests commonly used with file uploads.
///

View file

@ -1,6 +1,7 @@
//! Rejection response types.
use super::IntoResponse;
use crate::BoxError;
use crate::{
body::{box_body, BoxBody},
Error,
@ -8,7 +9,6 @@ use crate::{
use bytes::Bytes;
use http_body::Full;
use std::convert::Infallible;
use tower::BoxError;
define_rejection! {
#[status = INTERNAL_SERVER_ERROR]

View file

@ -1,4 +1,5 @@
use super::{rejection::*, take_body, Extension, FromRequest, RequestParts};
use crate::BoxError;
use async_trait::async_trait;
use bytes::Bytes;
use futures_util::stream::Stream;
@ -8,7 +9,6 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::BoxError;
#[async_trait]
impl<B> FromRequest<B> for Request<B>

View file

@ -16,7 +16,8 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::{util::Oneshot, Service};
use tower::util::Oneshot;
use tower_service::Service;
pin_project! {
/// The response future for [`OnMethod`](super::OnMethod).

View file

@ -7,7 +7,7 @@ use std::{
marker::PhantomData,
task::{Context, Poll},
};
use tower::Service;
use tower_service::Service;
/// An adapter that makes a [`Handler`] into a [`Service`].
///

View file

@ -7,6 +7,7 @@ use crate::{
routing::{EmptyRouter, MethodFilter},
service::HandleError,
util::Either,
BoxError,
};
use async_trait::async_trait;
use bytes::Bytes;
@ -18,7 +19,9 @@ use std::{
marker::PhantomData,
task::{Context, Poll},
};
use tower::{BoxError, Layer, Service, ServiceExt};
use tower::ServiceExt;
use tower_layer::Layer;
use tower_service::Service;
pub mod future;
mod into_service;

View file

@ -1,3 +1,4 @@
use crate::BoxError;
use crate::{
extract::{has_content_type, rejection::*, take_body, FromRequest, RequestParts},
response::IntoResponse,
@ -15,7 +16,6 @@ use std::{
convert::Infallible,
ops::{Deref, DerefMut},
};
use tower::BoxError;
/// JSON Extractor/Response
///

View file

@ -832,3 +832,6 @@ pub use tower_http::add_extension::{AddExtension, AddExtensionLayer};
#[doc(inline)]
pub use self::{error::Error, json::Json, routing::Router};
/// Alias for a type-erased error type.
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;

View file

@ -81,7 +81,7 @@ macro_rules! define_rejection {
impl $name {
pub(crate) fn from_err<E>(err: E) -> Self
where
E: Into<tower::BoxError>,
E: Into<crate::BoxError>,
{
Self(crate::Error::new(err))
}

View file

@ -1,11 +1,14 @@
use super::IntoResponse;
use crate::body::{box_body, BoxBody};
use crate::{
body::{box_body, BoxBody},
BoxError,
};
use bytes::Bytes;
use http::header::{HeaderMap, HeaderName, HeaderValue};
use http::{Response, StatusCode};
use http_body::{Body, Full};
use std::{convert::TryInto, fmt};
use tower::{util::Either, BoxError};
use tower::util::Either;
/// A response with headers.
///

View file

@ -2,7 +2,7 @@
use crate::{
body::{box_body, BoxBody},
Error,
BoxError, Error,
};
use bytes::Bytes;
use http::{header, HeaderMap, HeaderValue, Response, StatusCode};
@ -11,7 +11,6 @@ use http_body::{
Empty, Full,
};
use std::{borrow::Cow, convert::Infallible};
use tower::{util::Either, BoxError};
mod headers;
mod redirect;
@ -154,22 +153,6 @@ impl IntoResponse for Infallible {
}
}
impl<T, K> IntoResponse for Either<T, K>
where
T: IntoResponse,
K: IntoResponse,
{
type Body = BoxBody;
type BodyError = Error;
fn into_response(self) -> Response<Self::Body> {
match self {
Either::A(inner) => inner.into_response().map(box_body),
Either::B(inner) => inner.into_response().map(box_body),
}
}
}
impl<T, E> IntoResponse for Result<T, E>
where
T: IntoResponse,

View file

@ -28,6 +28,7 @@
//! ```
use crate::response::IntoResponse;
use crate::BoxError;
use bytes::Bytes;
use futures_util::{
ready,
@ -48,7 +49,6 @@ use std::{
};
use sync_wrapper::SyncWrapper;
use tokio::time::Sleep;
use tower::BoxError;
/// Create a new [`Sse`] response that will respond with the given stream of
/// [`Event`]s.

View file

@ -1,10 +1,11 @@
//! Future types.
use crate::{body::BoxBody, buffer::MpscBuffer, routing::FromEmptyRouter};
use crate::{body::BoxBody, buffer::MpscBuffer, routing::FromEmptyRouter, BoxError};
use futures_util::ready;
use http::{Request, Response};
use pin_project_lite::pin_project;
use std::{
convert::Infallible,
fmt,
future::Future,
pin::Pin,
@ -12,8 +13,9 @@ use std::{
};
use tower::{
util::{BoxService, Oneshot},
BoxError, Service, ServiceExt,
ServiceExt,
};
use tower_service::Service;
pub use super::or::ResponseFuture as OrResponseFuture;
@ -179,3 +181,9 @@ where
self.project().inner.poll(cx)
}
}
opaque_future! {
/// Response future from [`MakeRouteService`] services.
pub type MakeRouteServiceFuture<S> =
futures_util::future::Ready<Result<S, Infallible>>;
}

View file

@ -10,6 +10,7 @@ use crate::{
},
service::HandleError,
util::ByteStr,
BoxError,
};
use bytes::Bytes;
use http::{Request, Response, StatusCode, Uri};
@ -24,17 +25,19 @@ use std::{
};
use tower::{
util::{BoxService, ServiceExt},
BoxError, Layer, Service, ServiceBuilder,
ServiceBuilder,
};
use tower_http::map_response_body::MapResponseBodyLayer;
use tower_layer::Layer;
use tower_service::Service;
pub mod future;
mod method_filter;
mod or;
pub use self::{method_filter::MethodFilter, or::Or};
mod method_filter;
/// The router type for composing handlers and services.
#[derive(Debug, Clone)]
pub struct Router<S> {
@ -358,11 +361,11 @@ impl<S> Router<S> {
/// ```
///
/// [`MakeService`]: tower::make::MakeService
pub fn into_make_service(self) -> tower::make::Shared<S>
pub fn into_make_service(self) -> IntoMakeService<S>
where
S: Clone,
{
tower::make::Shared::new(self.svc)
IntoMakeService::new(self.svc)
}
/// Convert this router into a [`MakeService`], that will store `C`'s
@ -1019,6 +1022,39 @@ where
}
}
/// A [`MakeService`] that produces axum router services.
///
/// [`MakeService`]: tower::make::MakeService
#[derive(Debug, Clone)]
pub struct IntoMakeService<S> {
service: S,
}
impl<S> IntoMakeService<S> {
fn new(service: S) -> Self {
Self { service }
}
}
impl<S, T> Service<T> for IntoMakeService<S>
where
S: Clone,
{
type Response = S;
type Error = Infallible;
type Future = future::MakeRouteServiceFuture<S>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _target: T) -> Self::Future {
future::MakeRouteServiceFuture {
future: futures_util::future::ready(Ok(self.service.clone())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -10,7 +10,8 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::{util::Oneshot, Service, ServiceExt};
use tower::{util::Oneshot, ServiceExt};
use tower_service::Service;
/// [`tower::Service`] that is the combination of two routers.
///

View file

@ -4,6 +4,7 @@ use crate::{
body::{box_body, BoxBody},
response::IntoResponse,
util::{Either, EitherProj},
BoxError,
};
use bytes::Bytes;
use futures_util::ready;
@ -15,7 +16,8 @@ use std::{
pin::Pin,
task::{Context, Poll},
};
use tower::{util::Oneshot, BoxError, Service};
use tower::util::Oneshot;
use tower_service::Service;
pin_project! {
/// Response future for [`HandleError`](super::HandleError).

View file

@ -96,6 +96,7 @@
//! [`Redirect`]: tower_http::services::Redirect
//! [load shed]: tower::load_shed
use crate::BoxError;
use crate::{
body::BoxBody,
response::IntoResponse,
@ -108,7 +109,8 @@ use std::{
marker::PhantomData,
task::{Context, Poll},
};
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
use tower::{util::Oneshot, ServiceExt as _};
use tower_service::Service;
pub mod future;

View file

@ -1,5 +1,6 @@
#![allow(clippy::blacklisted_name)]
use crate::BoxError;
use crate::{
extract,
handler::{any, delete, get, on, patch, post, Handler},
@ -23,7 +24,8 @@ use std::{
task::{Context, Poll},
time::Duration,
};
use tower::{make::Shared, service_fn, BoxError, Service};
use tower::{make::Shared, service_fn};
use tower_service::Service;
mod get_to_head;
mod handle_error;

View file

@ -1,10 +1,8 @@
use super::*;
use crate::{extract::OriginalUri, response::IntoResponse, Json};
use serde_json::{json, Value};
use tower::{limit::ConcurrencyLimitLayer, timeout::TimeoutLayer};
use crate::{extract::OriginalUri, response::IntoResponse, Json};
use super::*;
#[tokio::test]
async fn basic() {
let one = Router::new()