Release Date: March 9, 2026 Full Changelog: https://github.com/Tuntii/RustAPI/compare/v0.1.397...v0.1.410
Benchmark Source of Truth: Current benchmark methodology and canonical performance claims live in docs/PERFORMANCE_BENCHMARKS.md. Historical release-specific benchmark notes should be treated as point-in-time snapshots unless they are linked from that document.
v0.1.410 is the Production Baseline release. It delivers everything you need to go from prototype to production-ready service with a single builder call — health probes, session management, rate limiting, observability tooling, and a suite of real-world examples.
| Feature | Crate | Impact |
|---|---|---|
| Production Defaults Preset | rustapi-core |
One-call production setup: health probes + tracing + request IDs |
| Health Check System | rustapi-core |
Built-in /health, /ready, /live with custom checks |
| Session Management | rustapi-extras |
Cookie-backed sessions with pluggable stores |
| Rate Limiting Strategies | rustapi-extras |
Fixed window, sliding window, and token bucket |
| CLI: bench & observability | cargo-rustapi |
New bench and observability subcommands |
| Multipart Streaming | rustapi-core |
Enhanced streaming multipart with progress tracking |
| 4 New Examples | rustapi-rs |
Auth, CRUD, Jobs, Streaming — ready to copy |
| 10+ Cookbook Recipes | docs/cookbook |
Migration guides, session auth, observability, error handling |
Go production-ready with a single call:
use rustapi_rs::prelude::*;
#[tokio::main]
async fn main() {
RustApi::new()
.production_defaults("my-service")
.run("0.0.0.0:3000")
.await;
}This enables:
RequestIdLayer— unique ID on every requestTracingLayer— structured logging with service metadata/health,/ready,/live— Kubernetes-compatible probes
Customizable via ProductionDefaultsConfig:
RustApi::new()
.production_defaults_with_config(
ProductionDefaultsConfig::new("my-service")
.version("1.2.3")
.tracing_level(tracing::Level::DEBUG)
.request_id(true)
.health_endpoints(true)
)
.run("0.0.0.0:3000")
.await;Full health check module with builder API, custom checks, and OpenAPI integration:
use rustapi_rs::prelude::*;
let health = HealthCheckBuilder::new(true)
.add_check("database", || async {
// Check database connectivity
HealthStatus::healthy()
})
.add_check("redis", || async {
HealthStatus::degraded("high latency".into())
})
.version("1.0.0")
.build();
RustApi::new()
.with_health_check(health)
.health_endpoints()
.run("0.0.0.0:3000")
.await;/health— aggregated status of all checks (200 or 503)/ready— dependency readiness (200 or 503)/live— lightweight liveness probe (always 200)- Configurable paths via
HealthEndpointConfig HealthStatusvariants:Healthy,Unhealthy { reason },Degraded { reason }
Cookie-backed session management with pluggable storage backends:
use rustapi_rs::prelude::*;
use rustapi_rs::extras::session::*;
let store = MemorySessionStore::new();
RustApi::new()
.layer(SessionLayer::new(
store,
SessionConfig::default()
.cookie_name("my_session")
.ttl(Duration::from_secs(3600))
.secure(true)
.http_only(true)
.same_site(SameSite::Lax)
))
.run("0.0.0.0:3000")
.await;Handler-side usage:
#[post("/login")]
async fn login(session: Session, body: Json<LoginRequest>) -> Result<Json<Value>> {
session.insert("user_id", &body.user_id).await?;
session.cycle_id().await; // CSRF protection
Ok(Json(json!({"status": "ok"})))
}Sessionextractor withget,insert,contains,destroy,cycle_idMemorySessionStorebuilt-in;SessionStoretrait for custom backends- Rolling sessions (refresh TTL on each access) by default
- Secure defaults:
HttpOnly,Secure,SameSite=Lax
Three strategies for different use cases:
use rustapi_rs::extras::rate_limit::*;
// Fixed window: 100 requests per 60 seconds
RustApi::new()
.layer(RateLimitLayer::new(100, Duration::from_secs(60))
.strategy(RateLimitStrategy::FixedWindow))
// Sliding window: smoother distribution
.layer(RateLimitLayer::new(100, Duration::from_secs(60))
.strategy(RateLimitStrategy::SlidingWindow))
// Token bucket: allows bursts
.layer(RateLimitLayer::new(100, Duration::from_secs(60))
.strategy(RateLimitStrategy::TokenBucket))- Per-IP tracking with
DashMap - Response headers:
X-RateLimit-Remaining,Retry-After - Returns
429 Too Many Requestswhen limit exceeded
Run the performance benchmark workflow:
cargo rustapi bench --warmup 5 --iterations 1000Surface observability assets and check production readiness:
cargo rustapi observability --checkChecks for production baseline docs, observability cookbook, benchmark script, and quality gate.
Expanded environment health checks with --strict mode that fails on warnings.
StreamingMultipart and StreamingMultipartField now support:
.bytes_read()— progress tracking.save_to(path)— stream directly to disk.save_as(path)— save with custom filename.into_uploaded_file()— convert toUploadedFile.field_count()— number of fields in the upload
Four production-ready examples added to crates/rustapi-rs/examples/:
| Example | Description |
|---|---|
auth_api.rs |
Session-based authentication with login/logout/refresh |
full_crud_api.rs |
Complete CRUD API with Arc<RwLock<HashMap>> state |
jobs_api.rs |
Background job queue with InMemoryBackend |
streaming_api.rs |
Server-sent events (SSE) streaming |
- Session Authentication — cookie-backed auth patterns
- Observability — monitoring and tracing setup
- Error Handling — structured error responses
- Custom Extractors — building your own extractors
- Middleware Debugging — layer inspection and troubleshooting
- Axum Migration — step-by-step migration guide from Axum
- Actix Migration — step-by-step migration guide from Actix-web
- OIDC/OAuth2 Production — production-grade OAuth2 setup
- Macro Attributes Reference — complete reference for all route macro attributes
New types available in rustapi_rs::prelude::*:
ProductionDefaultsConfig,HealthCheck,HealthCheckBuilder,HealthCheckResult,HealthStatus,HealthEndpointConfig
New modules in rustapi_rs::extras:::
session—Session,SessionLayer,SessionConfig,MemorySessionStore,SessionStore,SessionRecordrate_limit—RateLimitLayer,RateLimitStrategy
Release Date: February 26, 2026 Full Changelog: https://github.com/Tuntii/RustAPI/compare/v0.1.335...v0.1.397
Benchmark Source of Truth: Current benchmark methodology and canonical performance claims live in docs/PERFORMANCE_BENCHMARKS.md. Historical release-specific benchmark notes should be treated as point-in-time snapshots unless they are linked from that document.
This is the biggest feature release since v0.1.300. Seven major features land together, transforming RustAPI from a routing framework into a production-ready application platform.
| Feature | Crate | Impact |
|---|---|---|
| Compile-Time Extractor Safety | rustapi-macros |
Zero runtime surprises from body-consuming extractors |
| Typed Error Responses | rustapi-macros + rustapi-core |
Errors auto-reflected in OpenAPI spec |
| Pagination & HATEOAS | rustapi-core |
Offset + cursor pagination with RFC 8288 Link headers |
| Built-in Caching Layer | rustapi-extras |
LRU + ETag + 304 Not Modified out of the box |
| Event System & Lifecycle Hooks | rustapi-core |
In-process pub/sub + on_start / on_shutdown |
| Native Hot Reload | cargo-rustapi |
Zero-dependency file watcher, no cargo-watch needed |
| gRPC Support | rustapi-grpc |
First crates.io release — dual HTTP + gRPC server |
Body-consuming extractors (Json<T>, Body, ValidatedJson<T>) must now be the last handler parameter. The macro emits a clear compile error instead of silently failing at runtime:
// ✅ Compiles
#[get("/users")]
async fn ok(State(db): State<Db>, body: Json<CreateUser>) -> Result<Json<User>> { ... }
// ❌ Compile error: "Body-consuming extractors must be the last parameter"
#[get("/users")]
async fn bad(body: Json<CreateUser>, State(db): State<Db>) -> Result<Json<User>> { ... }Multiple body-consuming extractors in the same handler are also detected at compile time.
Declare possible error responses with #[errors()] — they appear automatically in Swagger UI:
#[get("/users/{id}")]
#[errors(404 = "User not found", 403 = "Insufficient permissions")]
async fn get_user(Path(id): Path<Uuid>) -> Result<Json<User>> { ... }Programmatic alternative: Route::error_response(404, "Not found").
async fn list(paginate: Paginate, State(db): State<Db>) -> Paginated<User> {
let (users, total) = db.find_users(paginate.offset(), paginate.limit()).await;
paginate.paginate(users, total)
}
// GET /users?page=2&per_page=20
// → { items: [...], meta: { page: 2, per_page: 20, total: 150, total_pages: 8 }, _links: {...} }
// → Link: <...?page=3&per_page=20>; rel="next", <...?page=1&per_page=20>; rel="prev"async fn feed(cursor: CursorPaginate) -> CursorPaginated<Post> {
let posts = db.posts_after(cursor.cursor(), cursor.limit()).await;
cursor.after(posts, next_cursor, has_more)
}Both include X-Total-Count and X-Total-Pages headers. All types in the prelude.
Full rewrite with production-grade features:
use rustapi_rs::prelude::*;
let app = RustApi::new()
.layer(
CacheBuilder::new()
.max_entries(5_000)
.default_ttl(Duration::from_secs(300))
.vary_by(&["Accept", "Authorization"])
.build()
);- LRU eviction with configurable
max_entries - ETag generation via FNV-1a hash + automatic
304 Not Modified - Cache-Control awareness (
no-cache,no-store) CacheHandlefor programmatic invalidation (by prefix, exact key, or clear all)
let bus = EventBus::new();
bus.on("user.created", |data| { println!("New user: {data}"); });
bus.emit("user.created", "alice@example.com");Supports sync and async handlers, fire-and-forget (emit) and await-all (emit_await).
RustApi::new()
.on_start(|| async { println!("🚀 Server starting..."); Ok(()) })
.on_shutdown(|| async { println!("👋 Graceful shutdown"); Ok(()) })
.run("0.0.0.0:8080").await;No more cargo install cargo-watch:
cargo rustapi watch # Watch mode with 300ms debounce
cargo rustapi run --watch # Same via run subcommand- Build-before-restart: Only restarts if
cargo buildsucceeds - Crash recovery: Watches for changes even after build failure
- Smart filtering: Ignores
target/,.git/, non-Rust files .hot_reload(true)builder API prints dev-mode banner
rustapi-grpc is now on crates.io for the first time:
[dependencies]
rustapi-rs = { version = "0.1.397", features = ["protocol-grpc"] }use rustapi_grpc::run_rustapi_and_grpc;
run_rustapi_and_grpc(http_app, grpc_router, "[::]:8080", "[::]:50051").await;Re-exports tonic and prost for seamless proto integration.
- Public API surface explicitly curated under
core,protocol,extras,preludemodules - API snapshot files (
api/public/) with CI drift check CONTRACT.mddefining SemVer contract, MSRV (1.78), deprecation policy- Feature taxonomy:
core-*,protocol-*,extras-*canonical names
- Clippy:
.map_or(false, ...)→.is_some_and(...)in cache middleware - Clippy: Nested
format!→ singleformat!in ETag generation - Publish pipeline:
rustapi-grpcadded to both publish scripts
# Cargo.toml
rustapi-rs = "0.1.397"
# For new features:
rustapi-rs = { version = "0.1.397", features = ["full"] }No breaking changes. Deprecated legacy feature aliases still work and will be removed no earlier than two minor releases after this announcement.
- Add lifecycle hooks, pagination, and cache (#139)
- Fix review feedback: deduplication, pagination validation, cache correctness (#140)
- docs: cookbook expansion and learning path improvements (#132)
- core: stabilize facade API surface, feature taxonomy, and public-api CI gate (#122)
- Add optional rustapi-grpc crate (tonic/prost) (#118)
- docs: multiple learning path and cookbook improvements (#109, #112, #120, #121, #123-126, #129)
Full Changelog: https://github.com/Tuntii/RustAPI/compare/v0.1.335...v0.1.397