Introducing Pencil: A Microframework Inspired By Flask For Rust

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!