Fanta

An opinionated framework for web development in rust.

Build Status

Fanta is a web framework that aims for developers to be productive and consistent across projects and teams. Its goals are to be: - Opinionated - Fast - Intuitive

Based heavily off of the work here: https://github.com/tokio-rs/tokio-minihttp

WARNING -- FANTA IS NOT READY, AND PROBABLY SHOULDN'T EVEN BE ON GITHUB YET

Opinionated

This is a work in progress

Fast

Initial tests of plain-text requests yeilds the following resuts:

Framework: Cowboy Requests/sec: 10982.93 Transfer/sec: 1.36MB Framework: Node (Koa) Requests/sec: 9592.82 Transfer/sec: 1.39MB Framework: Node (Express) Requests/sec: 5926.87 Transfer/sec: 1.22MB Framework: Phoenix/Elixir (prod mode) Requests/sec: 538.02 Transfer/sec: 132.93KB Framework: Rocket (dev mode) Requests/sec: 5537.87 Transfer/sec: 789.58KB Framework: Rocket (prod mode) Requests/sec: 18555.74 Transfer/sec: 2.58MB Framework: Fanta (dev mode) Requests/sec: 7362.82 Transfer/sec: 726.22KB Framework: Fanta (prod mode) Requests/sec: 39865.62 Transfer/sec: 3.84MB

Intuitive

Left to the developer to decide at this point!

Getting Started

To get started, check out the example app:

``` extern crate envlogger; extern crate futures; extern crate fanta; extern crate tokioproto; extern crate tokio_service; extern crate time;

[macro_use]

extern crate lazy_static;

use fanta::{App, Context, MiddlewareChain, Request, Response};

/** * Here we make a custom context. Contexts are the way that * Fanta passes data between middleware functions. Typically * this is where you'd add fields such as the currently * signed in user, or tracking sessions, etc. */

struct CustomContext { pub body: String, pub method: String, pub path: String }

impl CustomContext { fn new(context: CustomContext) -> CustomContext { CustomContext { body: context.body, method: context.method, path: context.path } } }

/** * The only important part about Contexts is that they * implement the Context trait. The Context trait only * requires a single method, getresponse. * * getresponse should create a Response object from * the current context. This is where you would hydrate * headers, body, and anything else custom that belongs * on the response. */

impl Context for CustomContext { fn get_response(&self) -> Response { let mut response = Response::new(); response.body(&self.body); response.header("Content-Type", "text/plain");

response

}

fn set_body(&mut self, body: String) { self.body = body; } }

/** * The generate_context function is pretty self explanatory. * It's the function that's passed in to the app that gets * called every time a new request into the app is made. It * takes the request and transforms it into Context. */

fn generatecontext(request: &Request) -> CustomContext { CustomContext { body: "".toowned(), method: request.method().toowned(), path: request.path().toowned() } }

/** * The app object must have a static lifetime. This is * just a way to generate static lifetime apps. */

lazystatic! { static ref APP: App = { let mut _app = App::::create(generatecontext);

/**
 * We have a single route with the root (/) path. It
 * then takes a vector of middleware to be run whenever
 * a request is made to that path.
 */
_app.get("/", vec![index]);

_app

}; }

/** * From above, this is the single function that's executed * when the / path is hit. Middleware functions take a * a Context, a MiddlewareChain (explained below,) and return * a Context. * * A MiddlewareChain is Fanta's way of representing the call * stack of middleware functions. It has a single method, * next which calls the next function in the middleawre * chain, which returns a new context. * * If chain.next() is not called, the chain simply does not * continue any further and the call stack returns back up. */

fn index(context: CustomContext, _chain: &MiddlewareChain) -> CustomContext { let mut context = CustomContext::new(context);

context.body = "Hello world".to_owned();

context }

/** * Start the app! */

fn main() { println!("Starting server...");

drop(envlogger::init()); App::start(&APP, "0.0.0.0".tostring(), "8080".to_string()); } ```