hitbox-tower 0.2.0

Hitbox integration for Tower framework
Documentation

hitbox-tower

Tower middleware integration for the Hitbox caching framework.

This crate provides [Cache], a Tower Layer that adds transparent HTTP caching to any Tower service. It evaluates requests against predicates, generates cache keys using extractors, and stores/retrieves responses through pluggable backends.

When to Use This Crate

Use hitbox-tower when you have a Tower-based HTTP service and want to add caching. This works for both:

  • Server-side: Wrap handlers in Axum, Hyper, or other Tower-based servers
  • Client-side: Wrap HTTP clients like hyper-util::Client for response caching

Core Concepts

  • [Cache]: A Tower Layer that wraps services with caching behavior. Use [Cache::builder()] to configure and construct the layer.

  • Predicate: Determines if a request/response should be cached. Returns Cacheable or NonCacheable. See [hitbox_http::predicates].

  • Extractor: Generates cache key parts from HTTP components (method, path, headers, query etc.). See [hitbox_http::extractors].

  • Backend: Storage for cached responses. Use hitbox_moka for in-memory, or other backends for distributed caching.

  • Policy: Controls TTL, stale-while-revalidate, and other timing behavior.

Quick Start

use std::time::Duration;
use hitbox::Config;
use hitbox::policy::PolicyConfig;
use hitbox_tower::Cache;
use hitbox_moka::MokaBackend;
use hitbox_http::extractors::Method;
use hitbox_http::predicates::{NeutralRequestPredicate, NeutralResponsePredicate};
use tower::{ServiceBuilder, service_fn};
# use http_body_util::Full;
# type Body = Full<bytes::Bytes>;

// 1. Create backend
let backend = MokaBackend::builder().max_entries(1000).build();

// 2. Configure caching behavior
let config = Config::builder()
    .request_predicate(NeutralRequestPredicate::new())
    .response_predicate(NeutralResponsePredicate::new())
    .extractor(Method::new())
    .policy(PolicyConfig::builder().ttl(Duration::from_secs(60)).build())
    .build();
# let _: Config<
#     NeutralRequestPredicate<Body>,
#     NeutralResponsePredicate<Body>,
#     Method<hitbox_http::extractors::NeutralExtractor<Body>>,
# > = config;

// 3. Build the cache layer
let cache_layer = Cache::builder()
    .backend(backend)
    .config(config)
    .build();

// 4. Apply to a Tower service
let service = ServiceBuilder::new()
    .layer(cache_layer)
    .service(service_fn(|_req: http::Request<Body>| async {
        Ok::<_, std::convert::Infallible>(http::Response::new(Body::new("Hello".into())))
    }));

Response Headers

The middleware adds a cache status header to every response:

Header Value Meaning
HIT Response served from cache
MISS Response fetched from upstream (may be cached for future requests)
STALE Stale cache entry served (background refresh may occur)

The default header name is x-cache-status. Customize it with [CacheBuilder::cache_status_header].

Main Types

Type Description
[Cache] Tower Layer — the main entry point
[CacheBuilder] Fluent builder for configuring the cache layer
[service::CacheService] The Tower Service that performs caching
[TowerUpstream] Adapter bridging Tower services to Hitbox's upstream interface

Re-exports

This crate re-exports commonly used types for convenience:

  • [http::Method], [http::StatusCode] — HTTP types for predicates
  • [CacheConfig] — Trait for cache configuration
  • [Config] — Generic cache configuration struct

For predicates and extractors, import from [hitbox_http]:

use hitbox_http::predicates::request::Method;
use hitbox_http::predicates::response::StatusCode;
use hitbox_http::extractors::{Method as MethodExtractor, path::PathExtractor};

Examples

For complete, runnable examples see the examples/ directory:

Server-side caching:

  • tower.rs — Plain Tower service with Hyper server
  • axum.rs — Axum web framework with per-route caching

Client-side caching:

Run with:

cargo run -p hitbox-examples --example tower
cargo run -p hitbox-examples --example axum
cargo run -p hitbox-examples --example hyper_client

Feature Flags

This crate has no feature flags. Backend selection is done by depending on the appropriate backend crate (e.g., hitbox-moka, hitbox-redis).