route-rs

Build Status Crates.io Badge

This crate is my attempt at a safe helper for mapping URL routes to handlers for rust web applications.

There are several routing libraries already available, but all of the ones I have been able to find share a common problem: path patterns are defined as strings, and URL parameters get parsed out at runtime and stashed in some kind of Map that handlers have to .get() and .unwrap() to access. I want to extract parameters without unwrapping, and I want rust's type system to ensure that I'm not making mistakes!

The current form is a macro, route_fn!, which creates a function mapping a path: &str to a member of an enum that you provide:

```rust

[macro use]

extern crate route;

[derive(Debug, PartialEq, Eq)]

enum Page<'a> { Home, BlogIndex, BlogPost(u32), BlogEdit(u32), User(&'a str), Account(&'a str), NotFound, }

routefn!(route -> Page { (/) => Page::Home, (/"blog") => Page::BlogIndex, (/"blog"/[id: u32]) => Page::BlogPost(id), (/"blog"/[id: u32]/"edit") => Page::BlogEdit(id), (/"blog"/[id: u32]/[]) => Page::BlogEdit(id), // ignored slug (/"u"/[handle]) => Page::User(handle), (/"me"[/rest..]) => Page::Account(rest), }, Page::NotFound); ```

You can now use the function Fn(&str) -> Page called 'route' created by the macro to match paths:

```rust

[test]

fn testroute() { asserteq!(route("/"), Page::Home); asserteq!(route("/blog"), Page::BlogIndex); asserteq!(route("/blog/42"), Page::BlogPost(42)); asserteq!(route("/blog/42/edit"), Page::BlogEdit(42)); asserteq!(route("/u/uniphil"), Page::User("uniphil")); asserteq!(route("/asdf"), Page::NotFound); asserteq!(route("/blog/abc"), Page::NotFound); assert_eq!(route("/me/a/b/c/d/e/f/g"), Page::Account("/a/b/c/d/e/f/g")); } ```

route() will return a member of Page, so if you want to map it to, say, an Iron handler:

```rust fn home_handler() -> IronResult { Ok(Response::with((status::Ok, "Hello world!"))) }

fn blogposthandler(id: u32) -> IronResult { Ok(Response::with((status::Ok, format!("This is blog post #{}", id)))) }

fn routehandler(req: &mut Request) -> IronResult { match route(req.url.path()) { Page::Home => homehandler(), Page::BlogPost(id) => blogposthandler(id), ... } }

fn main() { Iron::new(route_handler).http("localhost:3000").unwrap(); }