Introducing Pencil: A Microframework Inspired By Flask For Rust
Posted on Shipeng Feng's blog by Shipeng Feng (_fengsp) :A Minimal Application
extern crate pencil; use pencil::{Pencil, Request, Response, PencilResult}; fn hello(_: &mut Request) -> PencilResult { Ok(Response::from("Hello World!")) } fn main() { let mut app = Pencil::new("/web/hello"); app.get("/", "hello", hello); app.run("127.0.0.1:5000"); }
Routing
fn user(r: &mut Request) -> PencilResult { let user_id = r.view_args.get("user_id").unwrap(); Ok(format!("user {}", user_id).into()) } fn main() { // app here app.get("/user/<user_id:int>", "user", user); }
JSON Handling
use std::collections::BTreeMap; use pencil::jsonify; fn app_info(_: &mut Request) -> PencilResult { let mut d = BTreeMap::new(); d.insert("name", "hello"); d.insert("version", "0.1.0"); return jsonify(&d); } fn main() { // app here app.get("/info", "app_info", app_info); }
Error Handling
use pencil::HTTPError; fn page_not_found(_: HTTPError) -> PencilResult { let mut response = Response::from("Customized 404 :)"); response.status_code = 404; Ok(response) } fn main() { // app here app.httperrorhandler(404, page_not_found); }
Static Files
Just create the static folder under your application root path, it just works. Now you can visit http://localhost:5000/static/example.png and get your file. You can customize the static folder and static url path.
fn main() { // app here app.enable_static_file_handling(); }
Templating
Just create the templates folder under your application root path, it just works. You can customize the template folder.
<!DOCTYPE html> <html> <body> <h1> Hello {{ name }}! </h1> </body> </html>
fn hello_template(request: &mut Request) -> PencilResult { let mut context = BTreeMap::new(); context.insert("name".to_string(), "template".to_string()); return request.app.render_template("hello.html", &context); } fn main() { // app here app.register_template("hello.html"); app.get("/hello_template", "hello_template", hello_template); }
Logging
#[macro_use] extern crate log; extern crate env_logger; fn main() { // app here app.set_debug(true); app.set_log_level(); env_logger::init().unwrap(); debug!("* Running on http://localhost:5000/"); app.run("127.0.0.1:5000"); }
Redirects And Errors
use pencil::{redirect, abort}; fn github(_: &mut Request) -> PencilResult { return redirect("https://github.com/", 302); } fn login(_: &mut Request) -> PencilResult { return abort(401); } fn main() { // app here app.get("/github", "github", github); app.get("/login", "login", login); }
Request And Response Objects
They are really easy to use, check docs for more details.
fn search(request: &mut Request) -> PencilResult { let keyword = match request.args().get("q") { Some(q) => q as &str, None => "", }; Ok(Response::from(format!("You are searching for {}", keyword))) } fn main() { // app here app.get("/search", "search", search); }
Before/After Request
extern crate typemap; use typemap::Key; struct KeyType; struct Value(i32); impl Key for KeyType { type Value = Value; } fn before_request(request: &mut Request) -> Option<PencilResult> { request.extensions_data.insert::<KeyType>(Value(100)); None } fn main() { // app here app.before_request(before_request); }
Modular Applications
use pencil::method::Get; use pencil::Module; fn hi_module(_: &mut Request) -> PencilResult { Ok("Hi module.".into()) } fn main() { // app here let mut demo_module = Module::new("demo", "/web/hello/demo"); demo_module.route("/demo/hi", &[Get], "hi", hi_module); app.register_module(demo_module); }
Links
Have fun!