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

Very simple to implement local static file hosting, provide supports for rust_embed natively.

#[derive(RustEmbed)]
#[folder = "test/static"]
struct Assets;

let router = Router::new()
    .push(Router::with_path("dir1/<*path>").get(StaticDir::new("static/body")))
    .push(Router::with_path("test1.txt").get(
        StaticFile::new("test/static/test1.txt").chunk_size(1024))
    )
    .push(Router::with_path("test2.txt").get(
        Assets::get("test1.txt").unwrap().into_handler())
    )
    .push(Router::with_path("dir2/<**path>").get(
        static_embed::<Assets>().with_fallback("index.html"))
    );

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(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 salvo::prelude::*;
use salvo::extra::ws::WsHandler;
#[handler]
async fn connect(req: &mut Request, res: &mut Response) -> Result<(), StatusError> {
    WebSocketUpgrade::new()
        .upgrade(req, res, |mut ws| async move {
            while let Some(msg) = ws.recv().await {
                let msg = if let Ok(msg) = msg {
                    msg
                } else {
                    return;
                };

                if ws.send(msg).await.is_err() {
                    return;
                }
            }
        })
        .await
}
#[tokio::main]
async fn main() {
    let router = Router::new().handle(connect);
    Server::new(TcpListener::bind("127.0.0.1:7878")).serve(router).await;
}