Module iron::middleware [] [src]

This module contains Iron's middleware and handler system, the fundamental building blocks for handling HTTP requests and generating responses.

Handlers

A Handler will produce a Response given a Request. Most handlers are functions or closures that accept a &mut Request as an argument and return an IronResult containing a Response. An IronResult is returned instead of directly returning a Response in order to indicate a possibility of failure (e.g. database timeout).

Here's an example of a Handler:

use iron::prelude::*;
use iron::Handler;
use iron::status;

fn hello_handler(req: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello world!")))
};

Middleware

In situations involving more complex logic, it may be desirable to transform Requests passed to a Handler or altering Responses sent to the clients. For example, an authorization step could only allow requests sent by authorized users to be passed to a Handler and respond to all other requests with a 403 status code. To faciliate such use cases, Iron's middleware system allows Handlers to be extended by defining middleware, which will perform transformations.

There are three types of middleware:

  • A BeforeMiddleware alters a Request. It can be useful for handling control flow (e.g. routing and authorization).
  • An AroundMiddleware wraps a Handler, changing both the Response passed to the Handler and the returned Response.
  • An AfterMiddleware performs Response post-processing. It can be used for editing headers or logging Responses, but it should not be used for changing the body of a Response.

See the documentation for each middleware for more details.

Defining the middleware pipeline

A Chain is a Handler that wraps another Handler. It is used to attach middleware to the wrapped Handler using a link method corresponding to each type of middleware. A sample middleware pipeline is shown below:

use iron::prelude::*;
use iron::middleware::*;


struct RequestLoggingMiddleware;
impl BeforeMiddleware for RequestLoggingMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        println!("{:?}", req);
        Ok(())
    }
}

let mut chain = Chain::new(hello_handler);
chain.link_before(RequestLoggingMiddleware {});
// Since a Chain is a Handler, chain can be passed to Iron::new without any problems.
// Iron::new(chain).http("localhost:3000").unwrap();

The Request Handling Flow

A diagram modeling the entire middleware system process is shown below:

[b] = BeforeMiddleware
[a] = AfterMiddleware
[[h]] = AroundMiddleware
[h] = Handler

With no errors, the flow looks like:

[b] -> [b] -> [b] -> [[[[h]]]] -> [a] -> [a] -> [a] -> [a]

A request first travels through all BeforeMiddleware, then a Response is generated by the Handler, which can be an arbitrary nesting of AroundMiddleware, then all AfterMiddleware are called with both the Request and Response. After all AfterMiddleware have been fired, the response is written back to the client.

Iron's error handling system is pragmatic and focuses on tracking two pieces of information for error receivers (other middleware):

  • The cause of the error
  • The result (what to do about) the error.

The cause of the error is represented simply by the error itself, and the result of the error, representing the action to take in response to the error, is a complete Response, which will be sent at the end of the error flow.

When an error is thrown in Iron by any middleware or handler returning an Err variant with an IronError, the flow of the Request switches to the error flow, which proceeds to just call the catch method of middleware and sidesteps the Handler entirely, since there is already a Response in the error.

A Request can exit the error flow by returning an Ok from any of the catch methods. This resumes the flow at the middleware immediately following the middleware which handled the error. It is impossible to "go back" to an earlier middleware that was skipped.

Generally speaking, returning a 5XX error code means that the error flow should be entered by raising an explicit error. Dealing with 4XX errors is trickier, since the server may not want to recognize an error that is entirely the clients fault; handling of 4XX error codes is up to to each application and middleware author.

Middleware authors should be cognizant that their middleware may be skipped during the error flow. Anything that must be done to each Request or Response should be run during both the normal and error flow by implementing the catch method to also do the necessary action.

Structs

Chain

The middleware chain used in Iron.

Traits

AfterMiddleware

AfterMiddleware are fired after a Handler is called inside of a Chain.

AroundMiddleware

AroundMiddleware are used to wrap and replace the Handler in a Chain.

BeforeMiddleware

BeforeMiddleware are fired before a Handler is called inside of a Chain.

Handler

Handlers are responsible for handling requests by creating Responses from Requests.