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 code -> 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 with Hyper

Follow the getting started documentation from the Hyper crate to setup a Hyper service for your server. 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. The WebmachineDispatcher implementes the Hyper Service trait, so you can pass it to the make_service_fn.

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

```rust use hyper::server::Server; use webmachinerust::*; use webmachinerust::context::; use webmachine_rust::headers::; use serdejson::{Value, json}; use std::io::Read; use std::net::SocketAddr; use hyper::service::makeservice_fn; use std::convert::Infallible;

// setup the dispatcher, which maps paths to resources. The requirement of makeservicefn is // that it has a static lifetime fn dispatcher() -> WebmachineDispatcher<'static> { WebmachineDispatcher { routes: btreemap!{ "/myresource" => WebmachineResource { // Methods allowed on this resource allowedmethods: vec!["OPTIONS", "GET", "HEAD", "POST"], // if the resource exists callback resourceexists: callback(&|, _| true), // callback to render the response for the resource renderresponse: callback(&|, _| { let jsonresponse = json!({ "data": [1, 2, 3, 4] }); Some(jsonresponse.tostring()) }), // callback to process the post for the resource processpost: callback(&|, _| /* Handle the post here */ Ok(true) ), // default everything else .. WebmachineResource::default() } } } }

async fn startserver() -> Result<(), String> { // Create a Hyper server that delegates to the dispatcher let addr = "0.0.0.0:8080".parse().unwrap(); let makesvc = makeservicefn(|| async { Ok::<_, Infallible>(dispatcher()) }); match Server::trybind(&addr) { Ok(server) => { // start the actual server server.serve(make_svc).await; Ok(()) }, Err(err) => { error!("could not start server: {}", err); Err(format!("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.