8 releases
new 0.1.7 | Apr 25, 2025 |
---|---|
0.1.6 | Apr 25, 2025 |
#74 in Caching
145 downloads per month
39KB
624 lines
Actix Request-Reply Cache
A Redis-backed response caching middleware for Actix Web applications.
Features
- Redis-backed caching: Store HTTP responses in Redis for fast retrieval
- Configurable TTL: Set custom expiration times for cached responses
- Size limits: Control maximum response size to cache
- Flexible cache control: Use predicate functions to determine what should be cached
- Cache key customization: Set your own cache key prefix
- Standard compliant: Respects HTTP Cache-Control headers
- Minimal performance impact: Fast cache lookup and non-blocking I/O
Installation
Add this to your Cargo.toml
:
[dependencies]
actix-request-reply-cache = "0.1.0"
Basic Usage
use actix_web::{web, App, HttpServer};
use actix_request_reply_cache::RedisCacheMiddlewareBuilder;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Create the cache middleware with default settings
let cache = RedisCacheMiddlewareBuilder::new("redis://127.0.0.1:6379")
.build()
.await;
HttpServer::new(move || {
App::new()
.wrap(cache.clone())
.service(web::resource("/").to(|| async { "Hello world!" }))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Advanced Configuration
use actix_web::{web, App, HttpServer};
use actix_request_reply_cache::RedisCacheMiddlewareBuilder;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Create a more customized cache middleware
let cache = RedisCacheMiddlewareBuilder::new("redis://127.0.0.1:6379")
.ttl(300) // Cache for 5 minutes
.max_cacheable_size(512 * 1024) // Only cache responses <= 512KB
.cache_prefix("my-api-cache:") // Custom Redis key prefix
.cache_if(|ctx| {
// Only cache GET requests
if ctx.method != "GET" {
return false;
}
// Don't cache if Authorization header is present
if ctx.headers.contains_key("Authorization") {
return false;
}
// Don't cache admin routes
if ctx.path.starts_with("/admin") {
return false;
}
true
})
.build()
.await;
HttpServer::new(move || {
App::new()
.wrap(cache.clone())
.service(web::resource("/api/users").to(get_users))
.service(web::resource("/api/products").to(get_products))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
Cache Decision Context
The cache_if
predicate receives a CacheDecisionContext
with the following information:
method
: HTTP method string ("GET", "POST", etc.)path
: Request pathquery_string
: URL query parametersheaders
: HTTP request headersbody
: Request body as bytes
This allows for fine-grained control over what gets cached.
How It Works
- Incoming requests are intercepted by the middleware
- If Cache-Control headers specify no-cache/no-store, the request is processed normally
- Otherwise, a cache key is computed based on the request method, path, query string and body
- If a matching response is found in Redis, it's returned immediately with an X-Cache: HIT header
- If no match is found, the request is processed normally, and if the response is successful:
- The response is serialized and stored in Redis with the configured TTL
- The original response is returned to the client
License
This project is licensed under the MIT License.
Dependencies
~17–28MB
~494K SLoC