If you have ever worked with HTTP in Rust, you have probably referred to the hyper crate. Hyper provides a safe abstraction over HTTP and offers both a client and server type. It is also the foundation for frameworks such as Iron and Nickel.
One of the coolest things about hyper is that its server can be started with anything that
implements the Handler trait.
There is one required method called handle and it denotes how the type which implements it
should respond to an incoming connection.
handle has the following function signature:
fn handle<'a, 'k>(&'a self, Request<'a, 'k>, Response<'a, Fresh>)
As you can see it gives us access to a Request and Response type which are aptly named. If you take a look
at the documentation for these, you will find that they provide the basis to check
for HTTP headers or set the body of an HTTP response.
RegexSetThe regex crate recently added a type called a RegexSet.
This is a powerful construct in that it can match multiple patterns that you provide in a single
scan. Using this idea, I thought it would be fun to write a router with a RegexSet matching
requests under the hood.
The result of this is reroute. This crate provides a Router
type that can match patterns you provide and call corresponding functions accordingly. The functions have access
to the Request and Response along with a type that captures matches in the URI.
extern crate hyper;
extern crate reroute;
use hyper::Server;
use hyper::server::{Request, Response};
use reroute::{Captures, Router};
fn digit_handler(_: Request, res: Response, c: Captures) {
println!("captures: {:?}", c);
res.send(b"It works for digits!").unwrap();
}
fn main() {
let mut router = Router::new();
// Use raw strings so you don't need to escape patterns.
router.get(r"/(\d+)", digit_handler);
router.finalize().unwrap();
// You can pass the router to hyper's Server's handle function as it
// implements the Handle trait.
Server::http("127.0.0.1:3000").unwrap().handle(router).unwrap();
}
Since Router implements the Handler trait, hyper’s Server can use it to respond
to connections. With this in mind, you can write a REST app in a few lines and extend this
functionality to suit your own needs. The Captures type gives you matches in your URI that the regex
engine finds. So in the example above, if I do a GET against the route “/123”, c will be
Some(["/123", "123"]). This is a Vector of the matches returned from the RegexSet. You
can use any pattern with grouping that you like and the router will collect them for you. Of course
you don’t need to provide groups and can just add routes like “/v1/some/endpoint” as well.
Reroute surely isn’t as complete as Iron but its only goal is to route requests in an app.
Feel free to contact me through the email on my GitHub profile.