Salvo is simplest web framework in Rust world

Salvo is base on hyper, tokio. It only needs basic Rust knowledge to write powerful server.

use salvo::prelude::*;
#[handler]
async fn hello_world(res: &mut Response) {
    res.render("Hello world!");
}
#[tokio::main]
async fn main() {
    let router = Router::new().get(hello_world);
    let listener = TcpListener::bind("127.0.0.1:7878");
    Server::new(listener).serve(router).await;
}

http://localhost:7878

Hello world!

Chainable tree routing system

Chainable tree routing system let you write routing rules easily and chains. You can use regex to constraint parameters.

let debug_mode = true;
let admin_mode = true;
let router = Router::new()
    .get(handle)
    .push(
        Router::with_path("users").hoop(auth).post(handle).push(
            Router::with_path("< id>")
                .post(handle)
                .delete(handle),
        ),
    )
    .push(
        Router::with_path("users")
            .get(handle)
            .push(Router::with_path("< id>").get(handle)),
    )
    .then(|router| {
        if debug_mode {
            router.push(Router::with_path("debug").get(handle))
        } else {
            router
        }
    })
    .then(|router| {
        if admin_mode {
            parent.push(Router::with_path("admin").get(handle))
        } else {
            router
        }
    });

Serve Static Files

Serve your static HTML, CSS, and JavaScript files with ease by defining static routers. You can also serve the contents of multiple directories in the same router!

let router = Router::with_path("files/<*path>")
    .get(DirHandler::new(vec!["static/body", "static/girl"]));

Flexible Middleware Support

Choose from a number of already existing middlewares or create your own! Use them to verify and manipulate certain requests in your app.

let router = Router::new().push(
    Router::with_path("ws_chat")
        .get(FileHandler::new("examples/ws_chat.rs"))
).push(
    Router::new().hoop(deflate()).path("sse_chat")
        .get(FileHandler::new("sse_chat.rs"))
).push(
    Router::new().hoop(brotli()).path("todos")
        .get(FileHandler::new("todos.rs"))
).push(
    Router::new().hoop(gzip()).path("<*path>")
        .get(DirHandler::new("examples/"))
);

WebSocket Support

Use the power of WebSocket in your Salvo app! Build fast interactive user experiences with performance and scalability guaranteed.

use futures::{FutureExt, StreamExt};
use salvo::prelude::*;
use salvo::extra::ws::WsHandler;
#[handler]
async fn connect(req: &mut Request, res: &mut Response) -> Result<(), StatusError> {
    let fut = WsHandler::new().handle(req, res)?;
    let fut = async move {
        if let Some(ws) = fut.await {
            let (tx, rx) = ws.split();
            let fut = rx.forward(tx).map(|result| {
                if let Err(e) = result {
                    println!("websocket error: {:?}", e);
                }
            });
            tokio::task::spawn(fut);
        }
    };
    tokio::task::spawn(fut);
    Ok(())
}
#[tokio::main]
async fn main() {
    let router = Router::new().handle(connect);
    Server::new(TcpListener::bind("127.0.0.1:7878")).serve(router).await;
}