alexeuler / http_router

Expressive and effective router for rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Http router

This is a simple yet expressive router for http requests, abstract enough to be used with any http library on stable Rust.

Key features:

  • Very expressive routes with fully typed parameters
  • Can be used with any http lib
  • Few dependencies (only regex and lazy_static)

Getting started (for Hyper >= 0.12)

In your Cargo.toml

[dependencies]
http_router = "0.1"

In your lib.rs or main.rs:

#[macro_use]
extern crate http_router;

In your struct than implements Hyper Service:

// Each handler must have the same return type
// A good candidate might be a Box<Future<Item = hyper::Response, Error = Error>>
// The cost of this macro is next to zero, so it's ok to call it on each request
let router = router!(
    GET / => get_users,

    GET /users => get_users,
    POST /users => post_users,
    PUT /users/{user_id: usize} => put_users,
    DELETE /users/{user_id: usize} => delete_users,

    GET /users/{user_id: usize}/transactions => get_transactions,
    POST /users/{user_id: usize}/transactions => post_transactions,
    PUT /users/{user_id: usize}/transactions/{hash: String} => put_transactions,
    DELETE /users/{user_id: usize}/transactions/{hash: String} => delete_transactions,

    _ => not_found,
);

let path = req.uri.path();
let ctx = Context { ... };
// This will return a value of the matched handler's return type
// E.g. the aforementioned Box<Future<Item = hyper::Response, Error = Error>>
router(ctx, req.method.into(), path)

A file with handlers implementation

// Params from a route become handlers' typed params.
// If a param's type doesn't match (e.g. you supplied `sdf` as a user id, that must be `usize`)
// then this route counts as non-matching

type ServerFuture = Box<Future<Item = hyper::Response, Error = Error>>;

pub fn get_users(context: &Context) -> ServerFuture {
    ...
}

pub fn post_users(context: &Context) -> ServerFuture {
    ...
}

pub fn put_users(context: &Context, user_id: usize) -> ServerFuture {
    ...
}

pub fn delete_users(context: &Context, id: usize) -> ServerFuture {
    ...
}

pub fn get_transactions(context: &Context, user_id: usize) -> ServerFuture {
    ...
}

pub fn post_transactions(context: &Context, user_id: usize) -> ServerFuture {
    ...
}

pub fn put_transactions(context: &Context, user_id: usize, hash: String) -> ServerFuture {
    ...
}

pub fn delete_transactions(context: &Context, user_id: usize, hash: String) -> ServerFuture {
    ...
}

pub fn not_found(_context: &Context) -> ServerFuture {
    ...
}

See examples folder for a complete Hyper example

Using with other http libs

By default this crate is configured to be used with hyper >=0.12. If you want to use it with other libs, you might want to opt out of default features for this crate. So in your Cargo.toml:

[dependencies]
http_router = config = { version = "0.1", default-features = false}

The router! macro is independent of any framework. However, it returns a closure that takes 3 params - context, method and path. You need to supply these 3 params from your http lib.

context is a param of your user-defined type. e.g. Context. It will be passed as a first argument to all of your handlers. You can put there any values like database interfaces and http clients as you like.

method is a param of type Method defined in http_router lib. It is one of GET, POST, etc.

path is a &str which is the current route for a request.

Once you define these 3 params, you can use the router! macro for routing.

Benchmarks

Right now the router with 10 routes takes approx 50 microseconds for one match

About

Expressive and effective router for rust

License:MIT License


Languages

Language:Rust 100.0%