Velto is a minimal async web framework for Rust, built on async_tiny
Velto 1.3.0 has been released.
New in 1.3.0
- method aware routing (GET, POST, etc)
- enhanced route macro (
route!(app, GET "/signup" => show_signup))
Example
use velto::prelude::*;
/// GET handler for the signup page.
/// Renders the `signup.html` template from the `templates/` directory.
fn show_signup(_req: &Request) -> Response {
render!("signup.html", {
"title" => "Sign Up"
})
}
/// POST handler for form submission.
/// Parses the form body and responds with a confirmation message.
fn handle_signup(req: &Request) -> Response {
let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));
let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
let password = form.get("password").map(|s| s.as_str()).unwrap_or("");
let reply = format!("Signed up as: {}\nPassword: {}", username, password);
Response::from_string(reply).with_content_type("text/plain")
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
// Register GET and POST routes for "/signup"
// GET shows the form, POST handles submission
route!(app, GET "/signup" => show_signup);
route!(app, POST "/signup" => handle_signup);
// Serve static files from the "static/" directory
app.serve_static("static");
// Start the server on localhost:8080
app.run("127.0.0.1:8080").await
}
Velto 1.4.0 released (Sep 20, 2025)
Velto now supports multi-method routing with a single handler:
route!(app, [GET, POST] "/signup" => signup)- New
route_any!macro for registering a handler across all standard methods
Example
use velto::prelude::*;
fn signup(req: &Request) -> Response {
match req.method().as_str() {
"POST" => {
let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));
let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
let password = form.get("password").map(|s| s.as_str()).unwrap_or("");
let reply = format!("Signed up as: {}\nPassword: {}", username, password);
Response::from_string(reply).with_content_type("text/plain")
}
_ => {
render!("signup.html", {
"title" => "Sign Up"
})
}
}
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
// Register both GET and POST methods with one handler
route!(app, [GET, POST] "/signup" => signup);
app.serve_static("static");
app.run("127.0.0.1:8080").await
}
Velto 1.5.0 released (Sep 27, 2025)
New redirect helpers:
redirect("/dashboard")for redirecting to the specified locationredirect_with_statusfor redirecting with a custom status code, e.g.redirect_with_status("/new-url", 301);
Example
use velto::prelude::*;
fn signup(req: &Request) -> Response {
match req.method().as_str() {
"POST" => {
let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));
let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
let password = form.get("password").map(|s| s.as_str()).unwrap_or("");
let reply = format!("Signed up as: {}\nPassword: {}", username, password);
Response::from_string(reply).with_content_type("text/plain")
}
_ => {
render!("signup.html", {
"title" => "Sign Up"
})
}
}
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
// Register both GET and POST methods with one handler
route!(app, [GET, POST] "/signup" => signup);
app.serve_static("static");
app.run("127.0.0.1:8080").await
}
Velto 1.6.0 released (Oct 9, 2025)
Velto now automatically maps MIME types for all served files. For example, .html files are served with:
Content-Type: text/html; charset=utf-8
This ensures proper rendering across browsers and prevents issues like stylesheets being blocked due to missing MIME types.
Note: This release does not include any user-facing changes.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.