#hyper #router #routing #middleware #hyper-rs

routerify

A lightweight, idiomatic, composable and modular router implementation with middleware support for the Rust HTTP library hyper.rs

18 releases (stable)

2.0.2 May 8, 2021
2.0.1 Apr 22, 2021
2.0.0 Mar 14, 2021
2.0.0-beta-2 Feb 16, 2021
0.1.1 Mar 24, 2020

#6 in HTTP server

Download history 298/week @ 2021-01-21 191/week @ 2021-01-28 141/week @ 2021-02-04 284/week @ 2021-02-11 195/week @ 2021-02-18 198/week @ 2021-02-25 178/week @ 2021-03-04 133/week @ 2021-03-11 117/week @ 2021-03-18 139/week @ 2021-03-25 151/week @ 2021-04-01 121/week @ 2021-04-08 208/week @ 2021-04-15 280/week @ 2021-04-22 343/week @ 2021-04-29 142/week @ 2021-05-06

821 downloads per month
Used in less than 9 crates

MIT license

140KB
1.5K SLoC

Github Actions Status crates.io Documentation Contributors MIT

Routerify

Routerify provides a lightweight, idiomatic, composable and modular router implementation with middleware support for the Rust HTTP library hyper.

Routerify's core features:

To generate a quick server app using Routerify and hyper, please check out hyper-routerify-server-template.

Compiler support: requires rustc 1.48+

Benchmarks

Framework Language Requests/sec
hyper v0.14 Rust 1.50.0 144,583
routerify v2.0.0 with hyper v0.14 Rust 1.50.0 144,621
actix-web v3 Rust 1.50.0 131,292
warp v0.3 Rust 1.50.0 145,362
go-httprouter, branch master Go 1.16 130,662
Rocket, branch master Rust 1.50.0 130,045

For more info, please visit Benchmarks.

Install

Add this to your Cargo.toml file:

[dependencies]
routerify = "2.0.2"
hyper = "0.14"
tokio = { version = "1", features = ["full"] }

Basic Example

A simple example using Routerify with hyper would look like the following:

use hyper::{Body, Request, Response, Server, StatusCode};
// Import the routerify prelude traits.
use routerify::prelude::*;
use routerify::{Middleware, Router, RouterService, RequestInfo};
use std::{convert::Infallible, net::SocketAddr};

// Define an app state to share it across the route handlers and middlewares.
struct State(u64);

// A handler for "/" page.
async fn home_handler(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    // Access the app state.
    let state = req.data::<State>().unwrap();
    println!("State value: {}", state.0);

    Ok(Response::new(Body::from("Home page")))
}

// A handler for "/users/:userId" page.
async fn user_handler(req: Request<Body>) -> Result<Response<Body>, Infallible> {
    let user_id = req.param("userId").unwrap();
    Ok(Response::new(Body::from(format!("Hello {}", user_id))))
}

// A middleware which logs an http request.
async fn logger(req: Request<Body>) -> Result<Request<Body>, Infallible> {
    println!("{} {} {}", req.remote_addr(), req.method(), req.uri().path());
    Ok(req)
}

// Define an error handler function which will accept the `routerify::Error`
// and the request information and generates an appropriate response.
async fn error_handler(err: routerify::RouteError, _: RequestInfo) -> Response<Body> {
    eprintln!("{}", err);
    Response::builder()
        .status(StatusCode::INTERNAL_SERVER_ERROR)
        .body(Body::from(format!("Something went wrong: {}", err)))
        .unwrap()
}

// Create a `Router<Body, Infallible>` for response body type `hyper::Body`
// and for handler error type `Infallible`.
fn router() -> Router<Body, Infallible> {
    // Create a router and specify the logger middleware and the handlers.
    // Here, "Middleware::pre" means we're adding a pre middleware which will be executed
    // before any route handlers.
    Router::builder()
        // Specify the state data which will be available to every route handlers,
        // error handler and middlewares.
        .data(State(100))
        .middleware(Middleware::pre(logger))
        .get("/", home_handler)
        .get("/users/:userId", user_handler)
        .err_handler_with_info(error_handler)
        .build()
        .unwrap()
}

#[tokio::main]
async fn main() {
    let router = router();

    // Create a Service from the router above to handle incoming requests.
    let service = RouterService::new(router).unwrap();

    // The address on which the server will be listening.
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    // Create a server by passing the created service to `.serve` method.
    let server = Server::bind(&addr).serve(service);

    println!("App is running on: {}", addr);
    if let Err(err) = server.await {
        eprintln!("Server error: {}", err);
   }
}

Documentation

Please visit: Docs for an exhaustive documentation.

Examples

The examples.

Contributing

Your PRs and suggestions are always welcome.

Dependencies

~6.5MB
~132K SLoC