Volga
Fast & Easy Web Framework for Rust based on Tokio runtime for fun and painless microservices crafting.

Tutorial | API Docs
Features
- Supports HTTP/1.x
- Robust routing
- Custom middlewares
- Full Tokio compatibility
- Runs on stable Rust 1.80+
Getting Started
Dependencies
[dependencies]
volga = "0.1.9"
tokio = "1.40.0"
Asynchronous handler (Recommended):
use volga::{App, Results, AsyncEndpointsMapping};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello", |request| async {
Results::text("Hello World!")
}).await;
app.run().await
}
Synchronous handler:
use volga::{App, Results, SyncEndpointsMapping};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello", |request| {
Results::text("Hello World!")
}).await;
app.run().await
}
Custom middleware:
use volga::{App, Results, AsyncEndpointsMapping, AsyncMiddlewareMapping};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.use_middleware(|context, next| async move {
let response = next(context).await;
response
}).await;
app.map_get("/hello", |request| async {
Results::text("Hello World!")
}).await;
app.run().await
}
Reading query parameters
use volga::{App, AsyncEndpointsMapping, Results, Params};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello", |req| async move {
let params = req.params().unwrap();
let id = params.get("id").unwrap();
Results::text("Hello World!")
}).await;
app.run().await
}
Reading route parameters
use volga::{App, AsyncEndpointsMapping, Results, Params};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello/{id}", |req| async move {
let params = req.params().unwrap();
let id = params.get("id").unwrap();
Results::text("Hello World!")
}).await;
app.run().await
}
Reading JSON payload
use volga::{App, AsyncEndpointsMapping, Results, Payload};
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
age: i32
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_post("/hello", |req| async move {
let params: User = req.payload().unwrap();
Results::text("Hello World!")
}).await;
app.run().await
}
Returning a JSON
use volga::{App, AsyncEndpointsMapping, Results, Payload};
use serde::Serialize;
#[derive(Serialize)]
struct User {
name: String,
age: i32
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello", |req| async move {
let user: User = User {
name: "John",
age: 35
};
Results::json(&user) }).await;
app.run().await
}
Custom headers and Content-Type
use volga::{App, AsyncEndpointsMapping, Results, ResponseContext};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::build("127.0.0.1:7878").await?;
app.map_get("/hello", |req| async move {
let mut headers = HashMap::new();
headers.insert(String::from("x-api-key"), String::from("some api key"));
Results::from(ResponseContext {
content: Box::new(String::from("Hello World!")),
headers: Some(headers),
content_type: Some(mime::TEXT_PLAIN)
})
}).await;
app.run().await
}
Performance
Tested a single instance on a laptop using 1 thread and 200 connections and under configuration:
OS: Arch Linux
CPU: Intel i7-8665U (8) @ 4.800GHz
RAM: 31686MiB
Results
Running 10s test @ http://127.0.0.1:7878/hello
1 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.47ms 206.78us 3.82ms 63.96%
Req/Sec 136.88k 9.41k 160.43k 66.00%
1362576 requests in 10.07s, 168.93MB read
Requests/sec: 135335.46
Transfer/sec: 16.78MB