Quick Start

Installing Rust

If you don’t have Rust yet, we recommend you use rustup to manage your Rust installation. The official rust guideopen in new window has a wonderful section on getting started.

Salvo currently has a minimum supported Rust version 1.75. Running rustup update will ensure you have the latest and greatest Rust version available. As such, this guide assumes you are running Rust 1.75 or later.

Write first app

Create a new rust project:

cargo new hello_salvo --bin

Add this to Cargo.toml

[package]
name = "hello"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
salvo = "0.64.0"
tokio = { version = "1", features = ["macros"] }
tracing = "0.1"
tracing-subscriber = "0.3"

Create a simple function handler in the main.rs file, we call it hello, this function just render plain text "Hello world". In the main function, we need to create a root Router first, and then create a server and call it's bind function:

use salvo::prelude::*;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();

    let router = Router::new().get(hello);
    let acceptor = TcpListener::new("127.0.0.1:5800").bind().await;
    Server::new(acceptor).serve(router).await;
}

Congratulations! Your first app has done! Just run cargo run to run this app.

More about handler

There are many ways to write function handler.

  • The orginal format is:

    #[handler]
    async fn hello(_req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) {
        res.render("Hello world");
    }
    
  • You can omit function arguments if they are not used, like _req, _depot, _ctrl in this example:

    #[handler]
    async fn hello(res: &mut Response) {
        res.render("Hello world");
    }
    
  • Any type can be function handler's return value if it implements Writer. For example &str implements Writer and it will render string as plain text:

    #[handler]
    async fn hello(res: &mut Response) -> &'static str {// just return &str
        "Hello world"
    }
    
  • The more common situation is we want to return a Result<T, E> to implify error handling. If T and E implements Writer, Result<T, E> can be function handler's return type:

    #[handler]
    async fn hello(res: &mut Response) -> Result<&'static str, ()> {// return Result
        Ok("Hello world")
    }
    

Use HTTP3

First you need to enable feature http3 in Cargo.toml, and then change main.rs like this:

use salvo::conn::rustls::{Keycert, RustlsConfig};
use salvo::prelude::*;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();
    let cert = include_bytes!("../certs/cert.pem").to_vec();
    let key = include_bytes!("../certs/key.pem").to_vec();

    let router = Router::new().get(hello);
    let config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));
    let listener = TcpListener::new(("127.0.0.1", 5800)).rustls(config.clone());

    let acceptor = QuinnListener::new(config, ("127.0.0.1", 5800))
        .join(listener)
        .bind()
        .await;

    Server::new(acceptor).serve(router).await;
}
[package]
name = "example-hello-h3"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
salvo = { workspace = true, features = ["quinn"] }
tokio = { version = "1", features = ["macros"] }
tracing = "0.1"
tracing-subscriber = "0.3"

Run more examples

The absolute fastest way to start experimenting with Salvo is to clone the Salvo repository and run the included examples in the examples/ directory. For instance, the following set of commands runs the hello example:

git clone https://github.com/salvo-rs/salvo.git
cd salvo
cargo run --bin example-hello

There are numerous examples in the examples/ directory. They can all be run with cargo run --bin example-<name>.