Crate tower_http

source ·
Expand description

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,
    sensitive_headers::SetSensitiveRequestHeadersLayer,
    set_header::SetResponseHeaderLayer,
    trace::TraceLayer,
    validate_request::ValidateRequestHeaderLayer,
};
use tower::{ServiceBuilder, service_fn, BoxError};
use http::{Request, Response, header::{HeaderName, CONTENT_TYPE, AUTHORIZATION}};
use std::{sync::Arc, net::SocketAddr, convert::Infallible, iter::once};
use bytes::Bytes;
use http_body_util::Full;

// Our request handler. This is where we would implement the application logic
// for responding to HTTP requests...
async fn handler(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
    // ...
}

// Shared state across all request handlers --- in this case, a pool of database connections.
struct State {
    pool: DatabaseConnectionPool,
}

#[tokio::main]
async fn main() {
    // Construct the shared state.
    let state = State {
        pool: DatabaseConnectionPool::new(),
    };

    // Use tower's `ServiceBuilder` API to build a stack of tower middleware
    // wrapping our request handler.
    let service = ServiceBuilder::new()
        // Mark the `Authorization` request header as sensitive so it doesn't show in logs
        .layer(SetSensitiveRequestHeadersLayer::new(once(AUTHORIZATION)))
        // High level logging of requests and responses
        .layer(TraceLayer::new_for_http())
        // Share an `Arc<State>` with all requests
        .layer(AddExtensionLayer::new(Arc::new(state)))
        // Compress responses
        .layer(CompressionLayer::new())
        // Propagate `X-Request-Id`s from requests to responses
        .layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id")))
        // If the response has a known size set the `Content-Length` header
        .layer(SetResponseHeaderLayer::overriding(CONTENT_TYPE, content_length_from_response))
        // Authorize requests using a token
        .layer(ValidateRequestHeaderLayer::bearer("passwordlol"))
        // Accept only application/json, application/* and */* in a request's ACCEPT header
        .layer(ValidateRequestHeaderLayer::accept("application/json"))
        // Wrap a `Service` in our middleware stack
        .service_fn(handler);
}

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,
    trace::TraceLayer,
    classify::StatusInRangeAsFailures,
};
use tower::{ServiceBuilder, Service, ServiceExt};
use hyper_util::{rt::TokioExecutor, client::legacy::Client};
use http_body_util::Full;
use bytes::Bytes;
use http::{Request, HeaderValue, header::USER_AGENT};

#[tokio::main]
async fn main() {
let client = Client::builder(TokioExecutor::new()).build_http();
    let mut client = ServiceBuilder::new()
        // Add tracing and consider server errors and client
        // errors as failures.
        .layer(TraceLayer::new(
            StatusInRangeAsFailures::new(400..=599).into_make_classifier()
        ))
        // Set a `User-Agent` header on all requests.
        .layer(SetRequestHeaderLayer::overriding(
            USER_AGENT,
            HeaderValue::from_static("tower-http demo")
        ))
        // Decompress response bodies
        .layer(DecompressionLayer::new())
        // Wrap a `Client` in our middleware stack.
        // This is possible because `Client` implements
        // `tower::Service`.
        .service(client);

    // Make a request
    let request = Request::builder()
        .uri("http://example.com")
        .body(Full::<Bytes>::default())
        .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", features = ["trace"] }

You can use "full" to enable everything:

tower-http = { version = "0.1", 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.

Modules§

  • add_extensionadd-extension
    Middleware that clones a value into each request’s extensions.
  • authauth
    Authorization related middleware.
  • Body types.
  • catch_paniccatch-panic
    Convert panics into responses.
  • Tools for classifying responses as either success or failure.
  • compressioncompression-br or compression-deflate or compression-gzip or compression-zstd
    Middleware that compresses response bodies.
  • corscors
    Middleware which adds headers for CORS.
  • decompressiondecompression-br or decompression-deflate or decompression-gzip or decompression-zstd
    Middleware that decompresses request and response bodies.
  • follow_redirectfollow-redirect
    Middleware for following redirections.
  • limitlimit
    Middleware for limiting request bodies.
  • map_request_bodymap-request-body
    Apply a transformation to the request body.
  • map_response_bodymap-response-body
    Apply a transformation to the response body.
  • metricsmetrics
    Middlewares for adding metrics to services.
  • normalize_pathnormalize-path
    Middleware that normalizes paths.
  • propagate_headerpropagate-header
    Propagate a header from the request to the response.
  • request_idrequest-id
    Set and propagate request ids.
  • sensitive_headerssensitive-headers
    Middlewares that mark headers as sensitive.
  • Services that return responses without wrapping other Services.
  • set_headerset-header
    Middleware for setting headers on requests and responses.
  • set_statusset-status
    Middleware to override status codes.
  • timeouttimeout
    Middleware that applies a timeout to requests.
  • tracetrace
    Middleware that adds high level tracing to a Service.
  • validate_requestvalidate-request
    Middleware that validates requests.

Enums§

  • CompressionLevelcompression-br or compression-deflate or compression-gzip or compression-zstd or decompression-br or decompression-deflate or decompression-gzip or decompression-zstd
    Level of compression data should be compressed with.
  • The latency unit used to report latencies by middleware.

Traits§

Type Aliases§

  • Alias for a type-erased error type.