webmachine-rust

Port of Webmachine-Ruby (https://github.com/webmachine/webmachine-ruby) to Rust.

Build Status

webmachine-rust is a port of the Ruby version of webmachine. It implements a finite state machine for the HTTP protocol that provides semantic HTTP handling (based on the diagram from the webmachine project). It is basically a HTTP toolkit for building HTTP-friendly applications using the Hyper rust crate.

Webmachine-rust works with Hyper and sits between the Hyper Handler and your application code. It provides a resource struct with callbacks to handle the decisions required as the state machine is executed against the request with the following sequence.

REQUEST -> Hyper Handler -> WebmachineDispatcher -> WebmachineResource -> Your application -> WebmachineResponse -> Hyper -> RESPONSE

Features

Missing Features

Currently, the following features from webmachine-ruby have not been implemented:

Implementation Deficiencies:

This implementation has the following deficiencies:

Getting started

Follow the getting started documentation from the Hyper crate to setup a Hyper Handler for your server. Then from the handle function, you need to define a WebmachineDispatcher that maps resource paths to your webmachine resources (WebmachineResource). Each WebmachineResource defines all the callbacks (via Closures) and values required to implement a resource.

Note: This example uses the maplit crate to provide the btreemap macro and the log crate for the logging macros.

```rust use std::sync::Arc; use hyper::server::{Handler, Server, Request, Response}; use webmachinerust::*; use webmachinerust::context::; use webmachine_rust::headers::; use rustc_serialize::json::Json;

struct ServerHandler { }

impl Handler for ServerHandler {

 fn handle(&self, req: Request, res: Response) {
     // setup the dispatcher, which maps paths to resources
     let dispatcher = WebmachineDispatcher::new(
         btreemap!{
             "/myresource".to_string() => Arc::new(WebmachineResource {
                 // Methods allowed on this resource
                 allowed_methods: vec!["OPTIONS".to_string(), "GET".to_string(),
                    "HEAD".to_string(), "POST".to_string()],
                 // if the resource exists callback
                 resource_exists: Box::new(|context| true),
                 // callback to render the response for the resource
                 render_response: Box::new(|_| {
                     let mut data = vec![Json::I64(1), Json::I64(2), Json::I64(3),
                        Json::I64(4)];
                     let json_response = Json::Object(btreemap!{
                        "data".to_string() => Json::Array(data) });
                     Some(json_response.to_string())
                 }),
                 // callback to process the post for the resource
                 process_post: Box::new(|context|  /* Handle the post here */ Ok(true) ),
                 // default everything else
                 .. WebmachineResource::default()
             })
         }
     );
     // then dispatch the request to the web machine.
     match dispatcher.dispatch(req, res) {
         Ok(_) => (),
         Err(err) => warn!("Error generating response - {}", err)
     };
 }

}

pub fn startserver() { match Server::http(format!("0.0.0.0:0").asstr()) { Ok(mut server) => { // It is important to turn keep alive off server.keep_alive(None); server.handle(ServerHandler {}); }, Err(err) => { error!("could not start server: {}", err); } } } ```

Example implementations

For an example of a project using this crate, have a look at the Pact Mock Server from the Pact reference implementation.