Salvo is a web server framework written in Rust

Salvo is a rust web framework built on top of tokio and hyper.

use salvo::prelude::*;
#[fn_handler]
async fn hello_world(res: &mut Response) {
    res.render_plain_text("Hello World!");
}
#[tokio::main]
async fn main() {
    let router = Router::new().get(hello_world);
    Server::new(router).bind(([0, 0, 0, 0], 7878)).await;
}

http://localhost:7878

Hello World!

Tree-like Routing System

Tree-like 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::new().path("users").before(auth).post(handle).push(
        Router::new().path("< id:/\d+/>").post(handle).delete(handle)
    ),
).push(Router::new().path("users").get(handle).push(
        Router::new().path("< id:/\d+/>").get(handle)
    ),
).push_when(|_|if debug_mode {
        Some(Router::new().path("debug").get(handle))
    } else {
        None
}).visit(|parent|{
    if admin_mode {
        parent.push(Router::new().path("admin").get(handle))
    } else {
        parent
    }
});

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::new()
    .path("files/<*path>")
    .get(StaticDir::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 before they reach your handler or after handler.

let router = Router::new().push(
    Router::new().path("ws_chat")
        .get(StaticFile::new("examples/ws_chat.rs"))
).push(
    Router::new().after(deflate()).path("sse_chat")
        .get(StaticFile::new("sse_chat.rs"))
).push(
    Router::new().after(brotli()).path("todos")
        .get(StaticFile::new("todos.rs"))
).push(
    Router::new().after(gzip()).path("<*path>")
        .get(StaticDir::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 tokio;
use salvo::prelude::*;
use salvo_extra::ws::WsHandler;
#[fn_handler]
async fn connect(req: &mut Request, res: &mut Response) -> Result<(), HttpError> {
    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 {
                    eprintln!("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(router).bind(([0, 0, 0, 0], 7878)).await;
}