async fn(HttpRequest) -> Result<HttpResponse, Error>
Overview
tower-http is a library that provides HTTP-specific middleware and utilities built on top of
tower.
All middleware uses the http and http-body crates as the HTTP abstractions. That means
they're compatible with any library or framework that also uses those crates, such as
hyper, tonic, and warp.
Example server
This example shows how to apply middleware from tower-http to a Service
and then run
that service using hyper.
use tower_http::{
add_extension::AddExtensionLayer,
compression::CompressionLayer,
propagate_header::PropagateHeaderLayer,
auth::RequireAuthorizationLayer,
sensitive_headers::SetSensitiveRequestHeadersLayer,
set_header::SetResponseHeaderLayer,
trace::TraceLayer,
};
use tower::{ServiceBuilder, service_fn, make::Shared};
use http::{Request, Response, header::{HeaderName, CONTENT_TYPE, AUTHORIZATION}};
use hyper::{Body, Error, server::Server, service::make_service_fn};
use std::{sync::Arc, net::SocketAddr, convert::Infallible, iter::once};
# struct DatabaseConnectionPool;
# impl DatabaseConnectionPool {
# fn new() -> DatabaseConnectionPool { DatabaseConnectionPool }
# }
# fn content_length_from_response<B>(_: &http::Response<B>) -> Option<http::HeaderValue> { None }
# async fn update_in_flight_requests_metric(count: usize) {}
async fn handler(request: Request<Body>) -> Result<Response<Body>, Error> {
# todo!()
}
struct State {
pool: DatabaseConnectionPool,
}
#[tokio::main]
async fn main() {
let state = State {
pool: DatabaseConnectionPool::new(),
};
let service = ServiceBuilder::new()
.layer(SetSensitiveRequestHeadersLayer::new(once(AUTHORIZATION)))
.layer(TraceLayer::new_for_http())
.layer(AddExtensionLayer::new(Arc::new(state)))
.layer(CompressionLayer::new())
.layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id")))
.layer(SetResponseHeaderLayer::overriding(CONTENT_TYPE, content_length_from_response))
.layer(RequireAuthorizationLayer::bearer("passwordlol"))
.service_fn(handler);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
Server::bind(&addr)
.serve(Shared::new(service))
.await
.expect("server error");
}
Keep in mind that while this example uses hyper, tower-http supports any HTTP
client/server implementation that uses the http and http-body crates.
Example client
tower-http middleware can also be applied to HTTP clients:
use tower_http::{
decompression::DecompressionLayer,
set_header::SetRequestHeaderLayer,
};
use tower::{ServiceBuilder, Service, ServiceExt};
use hyper::Body;
use http::{Request, Response, HeaderValue, header::USER_AGENT};
#[tokio::main]
async fn main() {
let mut client = ServiceBuilder::new()
.layer(SetRequestHeaderLayer::<_, Body>::overriding(
USER_AGENT,
HeaderValue::from_static("tower-http demo")
))
.layer(DecompressionLayer::new())
.service(hyper::Client::new());
let request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
let response = client
.ready()
.await
.unwrap()
.call(request)
.await
.unwrap();
}
Feature Flags
All middleware are disabled by default and can be enabled using cargo features.
For example, to enable the Trace
middleware, add the "trace" feature flag in
your Cargo.toml
:
tower-http = { version = "0.1.0", features = ["trace"] }
You can use "full"
to enable everything:
tower-http = { version = "0.1.0", features = ["full"] }
Getting Help
If you're new to tower its guides might help. In the tower-http repo we also have a number
of examples showing how to put everything together. You're also welcome to ask in
the #tower
Discord channel or open an issue with your question.