12 stable releases

1.9.0 Oct 26, 2025
1.8.0 Oct 20, 2025
1.5.0 Sep 27, 2025
0.1.2 Aug 17, 2025

#355 in HTTP server

MIT license

35KB
471 lines

🚀 Velto

A minimal async web framework for Rust, built for clarity, speed, and joy.

Crates.io GitHub Actions Workflow Status Docs.rs License: MIT


✨ Features

  • 🧭 Intuitive routing with route!(...) and route_any!(...) macros
  • 🧵 Templating with render!, {% include %}, and {% extends %} support
  • ⚡ Fully async, powered by async_tiny
  • 🔄 LiveReload support in development mode
  • 📁 Static file serving with zero config
  • 🔌 Global middleware support via App::use_middleware()
  • 🧠 Minimal boilerplate via velto::prelude
  • 🧪 Built-in testing with TestRequest
  • 🛠 First-class CLI support via velto-cli

📦 Installation

Add Velto to your Cargo.toml:

[dependencies]
velto = "1.9.0"

Or use velto-cli to scaffold a new project instantly:

cargo install velto-cli
velto new my-app
cd my-app
velto run

🚀 Quick Start

use velto::prelude::*;
use velto::middleware::logger; // Built-in middleware

fn homepage(_req: &Request) -> Response {
    render!("index.html", {
        "title" => "Welcome to Velto",
        "message" => "Fast. Clean. Rusty."
    })
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();
    app.use_middleware(logger); // Add middleware
    app.enable_dev_mode();      // Enables LiveReload
    route!(app, "/" => homepage);
    app.serve_static("static");
    app.run("127.0.0.1:8080").await
}

🔌 Middleware

Velto supports global middleware functions that run before and/or after route handlers.
Use App::use_middleware() to register middleware like logging, authentication, or header injection.

Example: Logger Middleware

pub fn logger(req: &Request, next: &dyn Fn(&Request) -> Response) -> Response {
    println!("📥 {} {}", req.method(), req.url());
    let res = next(req);
    println!("📤 Responded with {}", res.status_code());
    res
}
  • Middleware is synchronous and composable
  • Multiple middleware are executed in registration order
  • Built-in logger middleware is available in velto::middleware

🔄 LiveReload

Velto automatically watches your static/ and templates/ directories in dev mode.
When a file changes, connected browsers reload instantly via WebSocket.

No setup required. Just call:

app.enable_dev_mode();

🧪 Testing

Velto includes a built-in TestRequest type for simulating requests in unit tests:

#[test]
fn test_homepage() {
    let mut app = App::new();
    route!(app, "/" => |_req| {
        Response::from_string("Hello, test!")
    });

    let res = velto::test::TestRequest::new("GET", "/").send(&app);
    assert_eq!(res.status_code(), 200);
    assert!(res.body().contains("Hello"));
}

No external test harness required — just write Rust tests and run cargo test.


🧰 Project Structure

Velto is organized into modular components for clarity and maintainability:

velto/
├── src/
│   ├── app.rs           # Core application logic
│   ├── dev.rs           # Dev mode toggles and helpers
│   ├── form.rs          # Form data parsing
│   ├── http_method.rs   # HTTP method utilities
│   ├── macros.rs        # Macros for render! and route!
│   ├── middleware.rs    # Middleware system and built-in examples
│   ├── prelude.rs       # Public API surface
│   ├── reload.rs        # LiveReload WebSocket + file watcher
│   ├── response.rs      # HTTP response utilities including redirect helpers
│   ├── router.rs        # Routing and handler dispatch
│   ├── template.rs      # Templating engine with include/inheritance
│   ├── test.rs          # TestRequest and internal test harness
│   ├── util.rs          # Utility functions (e.g., MIME types)
│   └── lib.rs           # Entry point

❓ Why Velto

Velto is for developers who want:

  • A fast, async-native web framework without the complexity of full-stack giants
  • Clean routing and templating without ceremony
  • Instant LiveReload for a smooth development loop
  • A modular codebase that grows with your project
  • A framework that feels like Rust — not like a port of something else

Whether you're building a personal site, a microservice, or a dev tool, Velto gives you just enough structure to stay productive — and just enough freedom to stay creative.


🔁 Migration from 0.x

Velto 1.0.0 introduced async support and LiveReload, but kept the public API familiar. Here's what changed:

Old (0.x) New (1.0.0)
fn main() #[tokio::main] async fn main()
Response<Cursor<Vec<u8>>> Response (no generics)
app.run(...) app.run(...).await
No LiveReload app.enable_dev_mode()

Most route handlers and macros (route!, render!) remain unchanged.
Just update your main() function and remove Cursor<Vec<u8>> from response types.


📄 License

MIT — free to use, modify, and distribute.


💬 Contributing

Velto is evolving rapidly. If you have ideas, feedback, or want to help shape its future, open an issue or submit a PR.
We welcome clean code, thoughtful design, and good vibes.

Dependencies

~8–21MB
~227K SLoC