pingora_web 0.1.4

Minimal routing, middleware, and logging (with request ID) for Pingora-based servers.
Documentation

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)
    }
}

// Add to router:
// router.get("/api/data", Arc::new(JsonHandler));

Static File Serving Example

use pingora_web::utils::ServeDir;

fn setup_router() -> Router {
    let mut router = Router::new();

    // Serve static files from ./public directory
    router.get("/static/{path}", Arc::new(ServeDir::new("./public")));

    // Or serve from current directory
    router.get("/assets/{path}", Arc::new(ServeDir::new(".")));

    router
}

License

Dual-licensed under either:

  • MIT
  • Apache-2.0

at your option.

Source repository: https://github.com/pingora-web/pingora_web Documentation: https://docs.rs/pingora_web