Crate webmachine_rust
source ·Expand description
webmachine-rust
Port of Webmachine-Ruby (https://github.com/webmachine/webmachine-ruby) to Rust.
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
- Handles the hard parts of content negotiation, conditional requests, and response codes for you.
- Provides a resource struct with points of extension to let you describe what is relevant about your particular resource.
Missing Features
Currently, the following features from webmachine-ruby have not been implemented:
- Visual debugger
- Streaming response bodies
Implementation Deficiencies:
This implementation has the following deficiencies:
- Automatically decoding request bodies and encoding response bodies.
- No easy mechanism to generate bodies with different content types (e.g. JSON vs. XML).
- No easy mechanism for handling sub-paths in a resource.
- Dynamically determining the methods allowed on the resource.
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.
use hyper::server::Server;
use webmachine_rust::*;
use webmachine_rust::context::*;
use webmachine_rust::headers::*;
use serde_json::{Value, json};
use std::io::Read;
use std::net::SocketAddr;
use hyper::service::make_service_fn;
use std::convert::Infallible;
use maplit::btreemap;
use tracing::error;
// setup the dispatcher, which maps paths to resources. The requirement of make_service_fn is
// that it has a static lifetime
fn dispatcher() -> WebmachineDispatcher<'static> {
  WebmachineDispatcher {
      routes: btreemap!{
         "/myresource" => WebmachineResource {
           // Methods allowed on this resource
           allowed_methods: vec!["OPTIONS", "GET", "HEAD", "POST"],
           // if the resource exists callback
           resource_exists: callback(&|_, _| true),
           // callback to render the response for the resource
           render_response: callback(&|_, _| {
               let json_response = json!({
                  "data": [1, 2, 3, 4]
               });
               Some(json_response.to_string())
           }),
           // callback to process the post for the resource
           process_post: callback(&|_, _|  /* Handle the post here */ Ok(true) ),
           // default everything else
           .. WebmachineResource::default()
         }
     }
  }
}
async fn start_server() -> Result<(), String> {
  // Create a Hyper server that delegates to the dispatcher
  let addr = "0.0.0.0:8080".parse().unwrap();
  let make_svc = make_service_fn(|_| async { Ok::<_, Infallible>(dispatcher()) });
  match Server::try_bind(&addr) {
    Ok(server) => {
      // start the actual server
      server.serve(make_svc).await;
    },
    Err(err) => {
      error!("could not start server: {}", err);
    }
  };
  Ok(())
}Example implementations
For an example of a project using this crate, have a look at the Pact Mock Server from the Pact reference implementation.
Modules
- Thecontent_negotiationmodule deals with handling media types, languages, charsets and encodings as per https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.
- Thecontextmodule encapsulates the context of the environment that the webmachine is executing in. Basically wraps the request and response.
- Theheadersdeals with parsing and formatting request and response headers
Macros
- Simple macro to convert a string to aHeaderValuestruct.
Structs
- The main hyper dispatcher
- Struct to represent a resource in webmachine
Functions
- Wrap a callback in a structure that is safe to call between threads
Type Definitions
- Type of a Webmachine resource callback