Crates.io | http_cache_tags |
lib.rs | http_cache_tags |
version | 0.1.0-alpha.5 |
created_at | 2025-07-24 16:57:37.822684+00 |
updated_at | 2025-07-30 13:14:35.525442+00 |
description | An experimental cache tagging library for Rust web frameworks |
homepage | |
repository | https://gitlab.com/dkluhzeb/http_cache_tags |
max_upload_size | |
id | 1766302 |
size | 105,744 |
Experimental: Alpha Release
This crate is in early development. APIs are unstable and may change without notice. Not recommended for production use yet.
This crate provides seamless integration of HTTP cache tagging and validation features into popular Rust web frameworks, including Actix-web and Axum.
It builds on the core [http_cache_tags_core
] library to deliver middleware, extractors, API handlers, and runtime components that enable tag-based cache invalidation and metadata resolution.
axum
): Middleware, extractors, and runtime for the Axum framework.actix
): Middleware, extractors, and runtime for Actix-web framework.ETag
and Last-Modified
.etag
, last_modified
, redis
, etc.).By default, the axum
integration and last_modified
support are enabled.
At least one server integration (axum
or actix
) and one validation header feature (etag
or last_modified
) must be activated for proper operation.
Feature | Description |
---|---|
axum |
Enable Axum framework middleware and extractors |
actix |
Enable Actix-web middleware and extractors |
config_file |
Load configuration from TOML file |
last_modified |
Support Last-Modified timestamps |
etag |
Generate and handle ETags |
redis |
Redis backend for cache metadata persistence |
The cache config maps URL routes to cache tags, and configures invalidation endpoints.
use http_cache_tags::axum::prelude::*;
let config = CacheConfig::builder()
.invalidation_api_route("/_invalidate")
.invalidation_api_secret("123abc")
.add_route_mapping("/blog/*", vec!["blog"])
.add_route_mapping("/media/*", vec!["media"])
.add_ignore_mapping("/blog/i-am-no-blog", vec!["blog"])
.redis_uri("redis://127.0.0.1/")
.build();
The CacheRuntime
composes the cache config with stores, API controllers, and middleware components.
use http_cache_tags::axum::prelude::*;
let config = CacheConfig::builder().build();
let runtime = CacheRuntime::builder()
.config(config)
// Optionally add a custom seeder to pre-populate cache tags
// .seeder(Box::new(MyCustomSeeder {}))
.build();
use http_cache_tags::axum::prelude::*;
use axum::{Router, routing::get};
use std::{net::SocketAddr, sync::Arc};
#[tokio::main]
async fn main() {
let config = CacheConfig::builder()
.invalidation_api_route("/_invalidate")
.add_route_mapping("/blog/*", vec!["blog"])
.build();
let runtime = CacheRuntime::builder().config(config).build();
let router = Router::new()
.route("/blog/{slug}", get(blog_handler));
let app = runtime.attach_to(router);
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn blog_handler(CacheMeta(meta): CacheMeta) -> String {
format!("Tags: {:?}, Last Modified: {:?}", meta.tags, meta.last_modified)
}
use actix_web::{App, HttpServer, web, HttpResponse};
use http_cache_tags::actix::prelude::*;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let config = CacheConfig::builder()
.invalidation_api_route("/_invalidate")
.add_route_mapping("/blog/*", vec!["blog"])
.build();
let runtime = CacheRuntime::builder().config(config).build();
let server = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(runtime.extractor()))
.wrap(runtime.cache_meta_middleware())
.wrap(runtime.cache_validation_middleware())
.service(runtime.invalidation_scope().unwrap())
.route("/blog/{slug}", web::get().to(blog_handler))
});
server.bind(("0.0.0.0", 3000))?.run().await
}
async fn blog_handler(meta: CacheMeta) -> HttpResponse {
HttpResponse::Ok().body(format!(
"Tags: {:?}, Last Modified: {:?}",
meta.tags, meta.last_modified
))
}
Implement CacheStoreSeeder
to prepopulate the cache store with tags or metadata on startup, useful for warming caches or integrating external systems.
use http_cache_tags::axum::prelude::*;
use std::{collections::HashSet, future::Future, pin::Pin};
struct MyCustomSeeder;
impl CacheStoreSeeder for MyCustomSeeder {
fn seed<'a>(
&'a self,
store: &'a (dyn CacheStore),
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {
// if `etag` feature is enabled
// store.delete_etag("home");
// store.set_etag("home", "v1");
// if `last_modified` is enabled
// store.delete_last_modified("home");
// store.set_last_modified("home", chrono::Utc::now());
})
}
}
This crate supports HTTP cache tagging and invalidation with detailed control over cache metadata such as ETag and Last-Modified headers.
Below are typical HTTP request examples demonstrating how to interact with the cache system:
If-Modified-Since
GET /blog/test HTTP/1.1
If-Modified-Since: Sun, 20 Jul 2025 23:12:31 +0000
If-None-Match
(ETag)GET /blog/test HTTP/1.1
If-None-Match: W/"82f493c74aaf8d7557ee619db325d6948f9cfb19"
POST /_invalidate HTTP/1.1
Content-Type: application/json
Authorization: Bearer my-secret
{
"tags": [
{ "tag": "blog", "last_modified": true, "etag": true }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "blog", "last_modified": null, "etag": null }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "blog", "last_modified": "2024-01-01T12:00:00Z" }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "blog", "last_modified": null }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "blog", "etag": true }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "blog", "etag": null }
]
}
POST /_invalidate HTTP/1.1
Content-Type: application/json
{
"tags": [
{ "tag": "user:42", "etag": true },
{ "tag": "product:99", "last_modified": true },
{ "tag": "stale:tag", "last_modified": null, "etag": null }
]
}
For more examples, see the examples/
folder containing HTTP request files demonstrating common usage patterns and advanced configurations.