vantus 0.2.0

Macro-first async Rust web platform with typed extraction, DI, and configuration binding.
Documentation

vantus

vantus is a macro-first async Rust web platform built around:

  • HostBuilder for bootstrapping
  • #[module] and #[controller] for application structure
  • typed extraction for path/query/body/config/service inputs
  • a lightweight DI container with singleton/scoped/transient lifetimes
  • layered configuration binding
  • an async runtime powered by tokio and hyper

Version 0.2.0 is a breaking macro-only release. Manual route construction and direct router registration are no longer part of the supported public application API.

Quick start

use vantus::{
    AppConfig, Config, FrameworkError, HostBuilder, Response, Service, TextBody, module,
};
use serde::Serialize;

#[derive(Default)]
struct GreetingService;

impl GreetingService {
    fn greet(&self, value: &str) -> String {
        format!("hello {value}")
    }
}

#[derive(Clone, Default)]
struct ApiModule;

#[module]
impl ApiModule {
    fn configure_services(
        &self,
        services: &mut vantus::ServiceCollection,
    ) -> Result<(), FrameworkError> {
        services.add_singleton(GreetingService);
        Ok(())
    }

    #[vantus::post("/greet")]
    fn greet(
        &self,
        config: Config<AppConfig>,
        service: Service<GreetingService>,
        body: TextBody,
    ) -> Result<Response, FrameworkError> {
        #[derive(Serialize)]
        struct Payload {
            service: String,
            message: String,
        }

        Response::json_serialized(&Payload {
            service: config.as_ref().service_name.clone(),
            message: service.as_ref().greet(body.as_str()),
        })
        .map_err(|error| FrameworkError::Internal(error.to_string()))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut builder = HostBuilder::new();
    builder.group("/api", |api| {
        api.module(ApiModule);
    });

    let host = builder.build()?;
    host.run().await?;
    Ok(())
}

See examples/macro_controller.rs and src/main.rs.

Supported authoring model

  • Use HostBuilder to configure files/env/profile loading and mount macro-defined modules.
  • Use #[module] for service registration, lifecycle hooks, and module route groups.
  • Use #[controller] for route-focused types when you want a separate controller abstraction.
  • Use typed inputs like Path<T>, Query<T>, TextBody, JsonBody<T>, Service<T>, Config<T>, and AppConfig.

Extraction model

The supported extraction inputs are:

  • RequestContext
  • Path<T>
  • Query<T>
  • QueryMap
  • TextBody
  • BodyBytes
  • JsonBody<T>
  • Service<T>
  • Config<T>
  • any T: FromConfiguration

Configuration

ConfigurationBuilder merges:

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

AppConfig provides the built-in production settings for:

  • service name
  • environment and profile
  • info/readiness toggles
  • server address
  • request timeout
  • graceful shutdown timeout
  • max request bytes
  • concurrency limit

Default platform module

WebPlatformModule provides a production-oriented starter set:

  • /health
  • /info
  • request logging
  • panic recovery middleware

Production notes

  • This crate is async-first and intended to run on tokio.
  • The public app-facing API is macro-first; internal routing primitives are reserved for framework internals and proc-macro expansion.
  • 0.2.0 is a breaking pre-1.0 release. See docs/migration-to-macros.md and CHANGELOG.md.

Verification

Release checks:

cargo fmt
cargo test
cargo clippy --all-targets --all-features -- -D warnings
cargo doc --no-deps
cargo package
cargo publish --dry-run