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.
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"));
```
```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// 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))) } ```