match_request

Macros for creating request routers in hyper.

Request paths can be matched using a more convenient readable syntax, or using full regular expressions. Specific methods can be listed under each path.

The return value of a match can be anything, though you'll usually want to return a boxed function to use as a view.

Pattern syntax

Matching a request path:

```rust use matchrequest::matchrequest; use hyper::Method;

let path = "/user/home"; let (value, params) = match_request!(&Method::GET, path, { "/login" => { GET => "serve login form", }, "/user/home" => { GET => "serve home page", } }).unwrap();

assert_eq!(value, "serve home page"); ```

Matching against multiple methods:

```rust use matchrequest::matchrequest; use hyper::Method;

let path = "/example"; let (value, params) = match_request!(&Method::DELETE, path, { "/login" => { GET => "serve login form", POST => "attempt login", }, "/example" => { GET => "serve example page", DELETE => "delete example page", } }).unwrap();

assert_eq!(value, "delete example page"); ```

Named path parameters:

```rust use matchrequest::matchrequest; use hyper::Method;

let path = "/posts/2020/my-blog-post"; let (value, params) = match_request!(&Method::GET, path, { "/posts/:year/:slug" => { GET => "serve blog post", }, }).unwrap();

asserteq!(params.get("year"), Some("2020")); asserteq!(params.get("slug"), Some("my-blog-post")); ```

Capturing the path tail:

```rust use matchrequest::matchrequest; use hyper::Method;

let path = "/static/vendor/img/icon.png"; let (value, params) = match_request!(&Method::GET, path, { "/static/*" => { GET => "serve static assets", }, }).unwrap();

// NOTE: the leading / is included assert_eq!(params.tail(), Some("/vendor/img/icon.png")); ```

Example router

```rust use matchrequest::{matchrequest, Error, Params}; use hyper::{Request, Response, Body}; use futures::future::{Future, BoxFuture};

// A boxed type definition for your async views. type BoxedView = Box< dyn Fn(Request, Params) -> BoxFuture<'static, Response>

;

// Like a regular match expression, match_request requires all // arms to return the same type. As each async fn will have a different // type, you'll likely need to put them in a Box first. This example macro // is one way to do it. macrorules! view { ($closure:expr) => {{ #[allow(unusedmut)] let mut closure = $closure; let b: BoxedView = Box::new(move |req, params| { Box::pin(closure(req, params)) }); b }}; }

// An example request router. async fn router(req: Request) -> Result, Error> { let method = req.method(); let path = req.uri().path();

// Attempt to match the request to a view.
let (handler, params) = match_request!(method, path, {
    "/foo/bar" => {
        GET => view!(foo_bar),
    },
    "/user/:name" => {
        GET => view!(user_profile),
    }
})?;

// Execute the view.
Ok(handler(req, params).await)

}

// Example views...

async fn foobar(req: Request, _params: Params) -> Response { Response::new(Body::from("Foo bar")) }

async fn userprofile(req: Request, params: Params) -> Response { // Extracting a parameter from the path. let name = params.get("name").unwrap(); Response::new(Body::from(format!("Profile for {}", name))) } ```