[](https://github.com/salvo-rs/salvo/actions)
[](https://github.com/salvo-rs/salvo/actions)
[](https://github.com/salvo-rs/salvo/actions)
[](https://crates.io/crates/salvo)
[](https://docs.rs/salvo)
[](https://github.com/rust-secure-code/safety-dance/)
[](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html)
[](https://codecov.io/gh/salvo-rs/salvo)
[](https://crates.io/crates/salvo)
[](https://salvo.rs)

Salvo is a powerful and simplest web server framework in Rust world.
You can view samples here, or view offical website.
Create a new rust project:
bash
cargo new hello_salvo --bin
Add this to Cargo.toml
toml
[dependencies]
salvo = { version = "0.18", features = ["full"] }
tokio = { version = "1", features = ["full"] }
Create a simple function handler in the main.rs file, we call it hello_world
, this function just render plain text "Hello World"
.
``` rust use salvo::prelude::*;
async fn hello_world(res: &mut Response) { res.render(Text::Plain("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:
```rust use salvo::prelude::*;
async fn hello_world() -> &'static str { "Hello World" }
async fn main() { let router = Router::new().get(hello_world); Server::new(TcpListener::bind("127.0.0.1:7878")).serve(router).await; } ```
There is no difference between Handler and Middleware, Middleware is just Handler. So you can write middlewares without to know concpets like associated type, generic type. You can write middleware if you can write function!!!*
Normally we write routing like this:
rust
Router::with_path("articles").get(list_articles).post(create_article);
Router::with_path("articles/<id>")
.get(show_article)
.patch(edit_article)
.delete(delete_article);
Often viewing articles and article lists does not require user login, but creating, editing, deleting articles, etc. require user login authentication permissions. The tree-like routing system in Salvo can meet this demand. We can write routers without user login together:
rust
Router::with_path("articles")
.get(list_articles)
.push(Router::with_path("<id>").get(show_article));
Then write the routers that require the user to login together, and use the corresponding middleware to verify whether the user is logged in:
rust
Router::with_path("articles")
.hoop(auth_check)
.post(list_articles)
.push(Router::with_path("<id>").patch(edit_article).delete(delete_article));
Although these two routes have the same path("articles")
, they can still be added to the same parent route at the same time, so the final route looks like this:
rust
Router::new()
.push(
Router::with_path("articles")
.get(list_articles)
.push(Router::with_path("<id>").get(show_article)),
)
.push(
Router::with_path("articles")
.hoop(auth_check)
.post(list_articles)
.push(Router::with_path("<id>").patch(edit_article).delete(delete_article)),
);
<id>
matches a fragment in the path, under normal circumstances, the article id
is just a number, which we can use regular expressions to restrict id
matching rules, r"<id:/\d+/>"
.
You can also use <*>
or <**>
to match all remaining path fragments. In order to make the code more readable, you can also add appropriate name to make the path semantics more clear, for example: <**file_path>
.
We can get file async by the function get_file
in Request
:
```rust
async fn upload(req: &mut Request, res: &mut Response) { let file = req.getfile("file").await; if let Some(file) = file { let dest = format!("temp/{}", file.filename().unwraporelse(|| "file".into())); if let Err(e) = tokio::fs::copy(&file.path, Path::new(&dest)).await { res.setstatuscode(StatusCode::INTERNALSERVERERROR); } else { res.render("Ok"); } } else { res.setstatuscode(StatusCode::BADREQUEST); } } ```
Your can find more examples in examples folder. You can run these examples with the following command:
cargo run --example basic_auth
You can use any example name you want to run instead of basic_auth
here.
There is a real and open source project use Salvo: https://github.com/driftluo/myblog.
Benchmark testing result can be found from here:
https://web-frameworks-benchmark.netlify.app/result?l=rust
https://www.techempower.com/benchmarks/#section=test&runid=785f3715-0f93-443c-8de0-10dca9424049
Contributions are absolutely, positively welcome and encouraged! Contributions come in many forms. You could:
All pull requests are code reviewed and tested by the CI. Note that unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Salvo by you shall be dual licensed under the MIT License, without any additional terms or conditions.
Salvo is an open source project. If you want to support Salvo, you can ☕ buy a coffee here.
Salvo is licensed under either of * Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) * MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)