25 releases
0.5.6 | Mar 6, 2022 |
---|---|
0.5.5 | Jan 28, 2020 |
0.5.3 | Nov 30, 2019 |
0.5.1 | Aug 24, 2018 |
0.3.5 | Nov 18, 2016 |
#483 in HTTP server
55KB
1K
SLoC
Canteen
Description
Canteen is the first project that I'm implementing in Rust. It's a clone of Flask, my very favorite Python web framework. There is code for an example implementation in the canteen-impl repository.
Usage
It's by no means complete, but I'm working on it, and it's now available on crates.io! To install and check it out, add the following to your Cargo.toml:
[dependencies]
canteen = "0.5"
The principle behind Canteen is simple -- handler functions are defined as simple
Rust functions that take a Request
and return a Response
. Handlers are then attached
to one or more routes and HTTP methods/verbs. Routes are specified using a simple
syntax that lets you define variables within them; variables that can then be
extracted to perform various operations. Currently, the following variable types can
be used:
<str:name>
will match anything inside a path segment, returns aString
<int:name>
will return a signed integer (i32
) from a path segment- ex:
cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)
will match"/api/foo/123"
but not"/api/foo/123.34"
or"/api/foo/bar"
- ex:
<uint:name>
will return an unsigned integer (u32
)<float:name>
does the same thing as theint
parameter definition, but matches numbers with decimal points and returns anf32
<path:name>
will greedily take all path data contained, returns aString
- ex:
cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)
will serve anything in the/static/
directory as a file
- ex:
After the handlers are attached to routes, the next step is to simply start the server. Any time a request is received, it is dispatched with the associated handler to a threadpool worker. The worker notifies the parent process when it's finished, and then the response is transmitted back to the client. Pretty straightforward stuff!
Example
extern crate canteen;
use canteen::*;
use canteen::utils;
fn hello_handler(req: &Request) -> Response {
let mut res = Response::new();
res.set_status(200);
res.set_content_type("text/plain");
res.append("Hello, world!");
res
}
fn double_handler(req: &Request) -> Response {
let to_dbl: i32 = req.get("to_dbl");
/* simpler response generation syntax */
utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
}
fn main() {
let cnt = Canteen::new();
// bind to the listening address
cnt.bind(("127.0.0.1", 8080));
// set the default route handler to show a 404 message
cnt.set_default(utils::err_404);
// respond to requests to / with "Hello, world!"
cnt.add_route("/", &[Method::Get], hello_handler);
// pull a variable from the path and do something with it
cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
// serve raw files from the /static/ directory
cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
cnt.run();
}
Dependencies
~7.5–10MB
~183K SLoC