vantus 0.3.0

Macro-first async Rust backend framework with explicit composition, typed extraction, and hardened HTTP defaults.
Documentation

vantus

vantus is a macro-first async Rust backend framework built around explicit composition, typed request extraction, and production-oriented HTTP defaults.

Companion docs:

Core model

  • Use HostBuilder to load configuration, apply runtime limits, and mount modules.
  • Use #[module] and #[controller] for route definition.
  • Construct application dependencies yourself with normal Rust constructors and pass them into modules/controllers explicitly.
  • Use request-derived handler inputs only: RequestContext, Path<T>, Query<T>, Header<T>, QueryMap, BodyBytes, TextBody, JsonBody<T>, RequestState<T>, IdentityState<T>, and safe optional variants.

Runtime DI-style handler injection is no longer part of the supported public API.

Quick start

use std::time::Duration;

use serde::Serialize;
use vantus::{HostBuilder, RequestContext, Response, TextBody, module};

#[derive(Clone)]
struct GreetingModule {
    service_name: String,
}

#[derive(Serialize)]
struct GreetingPayload {
    service: String,
    message: String,
}

#[module]
impl GreetingModule {
    #[vantus::post("/greet")]
    fn greet(&self, ctx: RequestContext, body: TextBody) -> GreetingPayload {
        GreetingPayload {
            service: self.service_name.clone(),
            message: format!("{}: {}", ctx.app_config().environment, body.as_str()),
        }
    }
}

fn main() {
    let mut builder = HostBuilder::new();
    builder.request_timeout(Duration::from_secs(5));
    builder.max_body_size(64 * 1024);
    builder.compose_with_config(|_configuration, app, context| {
        context.module(GreetingModule {
            service_name: app.service_name.clone(),
        });
        Ok(())
    });
    builder.build().run_blocking();
}

See examples/main.rs for the runnable example.

Request contracts

Route contracts are inferred from handler signatures and enforced before the handler runs.

  • JsonBody<T> requires Content-Type: application/json
  • TextBody requires Content-Type: text/plain
  • BodyBytes accepts any media type
  • handlers without a body extractor reject non-empty request bodies
  • GET, HEAD, and OPTIONS handlers cannot declare body extractors
  • wrong-method matches return 405 Method Not Allowed with an Allow header

Middleware

Attach middleware declaratively with #[middleware(Type)] on a module/controller impl or an individual route method.

  • middleware types must implement Middleware and Default
  • impl-level middleware wraps route-level middleware
  • repeated attributes run in source order

Observability

ObservabilityModule adds:

  • X-Request-Id generation using the configured IdGenerator
  • structured request logging
  • /live, /ready, /diag, and /metrics
  • readiness contributor registration
  • runtime counters and per-route latency totals

vantus does not install a global tracing subscriber or exporter for you. Wire those explicitly in your binary so logging, tracing, and metrics stay under application control.

The default ID generator is UuidIdGenerator. AtomicIdGenerator remains available for tests and local demos, but it is no longer the default.

Configuration

ConfigurationBuilder merges:

  • application.properties
  • application.{profile}.properties
  • environment variables with the configured prefix, default APP_

AppConfig remains the built-in runtime configuration model. For application-specific config, bind your own type from Configuration inside compose_with_config(...) and pass the resulting values into your modules explicitly.

Security and operations

  • HostBuilder::max_body_size(...) enforces request body size before middleware
  • HostBuilder::request_timeout(...) sets the outer request deadline
  • HostBuilder::rate_limiter(...) applies pre-middleware token-bucket throttling
  • HTTP/1.1 requests require a valid Host header
  • content-type and method/body mismatches are rejected early
  • TLS termination, CORS, compression, and auth helpers are intentionally left to middleware or a front proxy in this release
  • CI runs cargo audit and cargo deny
  • Dependabot is configured for Cargo crates and GitHub Actions updates

Publishing

Before publishing, walk through docs/publishing-checklist.md and confirm SECURITY.md still matches your disclosure workflow.

Optional CLI

Enable the cli feature when you want first-party runtime flag parsing for environment/profile selection, feature toggles, rate limiting, request limits, and startup dry-runs.

Verification

$env:CARGO_TARGET_DIR="target_plan"
cargo test --lib --tests
cargo test --examples --no-run
cargo test --doc
cargo clippy --all-targets --all-features -- -D warnings
cargo doc --no-deps