pingora_web
Minimal routing, middleware, and structured logging (with request ID) for servers built on Cloudflare's Pingora.
- Router with params (e.g.
/hi/{name})
- Async middleware (onion model)
- Request ID middleware enabled by default (
x-request-id)
- Tracing-friendly logging middleware
- Integrates with Pingora as an
HttpServerApp
Installation
[dependencies]
pingora_web = "0.1"
pingora = { version = "0.6" }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
Quick example
use async_trait::async_trait;
use pingora_web::{App, Handler, Request, Response, Router, TracingMiddleware};
use pingora::server::Server;
use pingora::services::listening::Service;
use std::sync::Arc;
struct Hello;
#[async_trait]
impl Handler for Hello {
async fn handle(&self, req: Request) -> Response {
let name = req.param("name").unwrap_or("world");
Response::text(200, format!("Hello {}", name))
}
}
fn main() {
tracing_subscriber::fmt()
.with_env_filter("info")
.init();
let mut router = Router::new();
router.get("/hi/{name}", Arc::new(Hello));
let mut app = App::new(router);
app.use_middleware(TracingMiddleware::new());
let mut server = Server::new(None).unwrap();
server.bootstrap();
let mut service = Service::new("Web Service HTTP".to_string(), app);
service.add_tcp("0.0.0.0:8080");
server.add_services(vec![Box::new(service)]);
server.run_forever().unwrap();
}
JSON Response Example
use serde::Serialize;
#[derive(Serialize)]
struct ApiResponse {
success: bool,
message: String,
data: Vec<String>,
}
struct JsonHandler;
#[async_trait]
impl Handler for JsonHandler {
async fn handle(&self, _req: Request) -> Response {
let response = ApiResponse {
success: true,
message: "Hello from JSON API".to_string(),
data: vec!["item1".to_string(), "item2".to_string()],
};
Response::json(200, response)
}
}
Static File Serving Example
use pingora_web::utils::ServeDir;
fn setup_router() -> Router {
let mut router = Router::new();
router.get("/static/{path}", Arc::new(ServeDir::new("./public")));
router.get("/assets/{path}", Arc::new(ServeDir::new(".")));
router
}
License
Dual-licensed under either:
at your option.
Source repository: https://github.com/pingora-web/pingora_web
Documentation: https://docs.rs/pingora_web