RONIN

Zero-allocation HTTP routing engine

Masterless. Disciplined. Self-contained.

Named after the masterless samurai - fast, disciplined, and self-contained. RONIN carries no excess. No dependencies. No allocations it doesn't need. A single warrior, purpose-built for routing.

Built for speed

Every design decision optimizes for throughput and minimal overhead.

O(k)
route lookup

Compressed radix trie. Lookup time proportional to key length, not route count.

0
dependencies

Only the Rust standard library. No external crates. Full control over every byte.

0-copy
parsing

Request parsing borrows directly from the receive buffer. No unnecessary copies.

Everything you need, nothing you don't

A focused feature set for building HTTP services in Rust.

/
Compressed Radix Trie

Routes stored in a compressed trie for O(k) lookup. Shared prefixes merged automatically.

:id
Path Parameters

Named parameters like /users/:id with zero-copy extraction from the request path.

*
Wildcard Routes

Catch-all patterns with *wildcard for static file serving and flexible routing.

{ }
Route Groups

Nest routers under shared prefixes. Organize APIs cleanly without duplication.

Thread-Per-Connection

Each connection handled on its own thread. Simple concurrency model, no runtime needed.

Keep-Alive

Persistent connections supported out of the box. Reuse TCP connections across requests.

Up and running in minutes

A minimal HTTP server with routing, path parameters, and JSON responses.

main.rs
use ronin::{Router, Request, Response};

fn main() {
    let mut router = Router::new();

    // Simple GET route
    router.get("/", |_req: &Request, res: &mut Response| {
        res.send("Hello, Ronin.");
    });

    // Path parameters
    router.get("/users/:id", |req: &Request, res: &mut Response| {
        let id = req.param("id").unwrap();
        res.json(&format!(r#"{{"user_id": "{}"}}"#, id));
    });

    // Route groups
    let mut api = Router::new();
    api.get("/health", |_req, res| {
        res.json(r#"{"status": "ok"}"#);
    });
    router.group("/api", api);

    // Wildcard route for static files
    router.get("/static/*path", |req: &Request, res: &mut Response| {
        let path = req.param("path").unwrap();
        res.send(&format!("Serving: {}", path));
    });

    router.listen("0.0.0.0:3000");
}

API at a glance

Core types and their methods.

Router

MethodSignatureDescription
newRouter::new() -> RouterCreate a new router instance
getrouter.get(path, handler)Register a GET handler
postrouter.post(path, handler)Register a POST handler
putrouter.put(path, handler)Register a PUT handler
deleterouter.delete(path, handler)Register a DELETE handler
grouprouter.group(prefix, sub_router)Nest a router under a prefix
listenrouter.listen(addr)Start accepting connections

Request

MethodSignatureDescription
methodreq.method() -> &strHTTP method
pathreq.path() -> &strRequest path
paramreq.param(name) -> Option<&str>Extract path parameter
headerreq.header(name) -> Option<&str>Get header value
bodyreq.body() -> &[u8]Raw request body

Response

MethodSignatureDescription
statusres.status(code)Set HTTP status code
headerres.header(name, value)Set response header
sendres.send(body)Send text response
jsonres.json(body)Send JSON response

Get started

Add RONIN to your Rust project with cargo.

cargo add ronin

Or add to Cargo.toml:

ronin = "0.1"
minimal server
use ronin::{Router, Request, Response};

fn main() {
    let mut router = Router::new();

    router.get("/", |_req, res| {
        res.send("Hello, Ronin.");
    });

    router.listen("0.0.0.0:3000");
}