Iron
Jonathan Reem Iron
A Type Driven Web Framework
About me
- <3 OSS, Rust
- SE at Terminal.com
- github.com/reem
Jonathan Reem Iron
Jonathan Reem Iron
Say Hello!
extern crate iron;
use iron::prelude::*;
use iron::status;
fn main() {
Iron::new(|req: &mut Request| {
Response::with((status::Ok, "Hello!"))
}).http(("127.0.0.1", 3000)).unwrap()
}
Jonathan Reem Iron
Let's Break it Down
extern crate iron;
use iron::prelude::*;
use iron::status;
fn main() {
Iron::new(|req: &mut Request| {
Response::with((status::Ok, "Hello!"))
}).http(("127.0.0.1", 3000)).unwrap()
}
Jonathan Reem Iron
Let's Break it Down
extern crate iron;
use iron::prelude::*;
use iron::status;
fn main() {
Iron::new(|req: &mut Request| {
Response::with((status::Ok, "Hello!"))
}).http(("127.0.0.1", 3000)).unwrap()
}
impl<H> Iron<H> where H: Handler {
pub fn new(handler: H) -> Iron<H>;
}
Jonathan Reem Iron
Handlers
pub trait Handler: Send + Sync + Any {
fn handle(&self, &mut Request) -> IronResult<Response>;
}
- Like "controllers", but less baggage
- Can be closures:
impl<F> Handler for F
where F: Send + Sync + Any,
F: Fn(&mut Request) -> IronResult<Response> {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
(*self)(req)
}
}
Jonathan Reem Iron
Handlers
pub trait Handler: Send + Sync + Any {
fn handle(&self, &mut Request) -> IronResult<Response>;
}
- All requests go through a Handler
- Can error but always produce a Response
- Accessed concurrently
- Can (and often do) contain other Handlers
- ex: Router, Mount, Static, Chain, &c.
Jonathan Reem Iron
Our Handler
|req: &mut Request| -> IronResult<Response> {
Ok(Response::with((status::Ok, "Hello!")))
}
What is Response::with?
impl Response {
pub fn with<M: Modifier<Self>>(modifier: M) -> Self {
Response::new().set(modifier)
}
}
Jonathan Reem Iron
Modifiers
Come from the `modifier` crate
pub trait Modifier<F: ?Sized> {
fn modify(self, &mut F);
}
pub trait Set {
fn set<M: Modifier<Self>>(mut self, modifier: M) -> Self where Self: Sized {
modifier.modify(&mut self);
self
}
fn set_mut<M: Modifier<Self>>(&mut self, modifier: M) -> &mut Self {
modifier.modify(self);
self
}
}
That's it!
Jonathan Reem Iron
Modifiers
Allow chaining with both `Self` and `&mut self`:
let res = get_response()
.set(status::Ok)
.set("This will become the body!")
.set(Path::new("./or/this/file.txt"))
.set(Redirect(Url::parse("localhost:3000/to/here")));
let response = &mut res;
response
.set_mut(status::Ok)
.set_mut("This will become the body!")
.set_mut(Path::new("./or/this/file.txt"))
.set_mut(Redirect(Url::parse("localhost:3000/to/here")));
Jonathan Reem Iron
Modifiers
Can define new Modifiers anywhere
pub struct NewHeaders(Headers);
impl Modifier<Response> for NewHeaders {
fn modify(self, response: &mut Response) {
response.headers.extend(self.0)
}
}
// Now we can do res.set(NewHeaders(headers))
Jonathan Reem Iron
Modifiers
Can be composed as tuples!
impl<T, M1, M2> Modifier<T> for (M1, M2)
where M1: Modifier<T>, M2: Modifier<T> {
fn modify(self, target: &mut T) {
self.0.modify(target);
self.1.modify(target);
}
}
// And so on...
(M1, M2..) implements Modifier if M* does
Jonathan Reem Iron
Coming back...
extern crate iron;
use iron::prelude::*;
use iron::status;
fn main() {
Iron::new(|req: &mut Request| {
Response::with((status::Ok, "Hello!"))
}).http(("127.0.0.1", 3000)).unwrap()
}
We now understand all of this!
Jonathan Reem Iron
Let's talk about Errors
What is an IronError?
pub struct IronError {
pub error: Box<Error + Send>,
pub response: Response
}
- IronError answers 2 questions:
- What happened?
- What should we do about it?
Jonathan Reem Iron
Middleware and Chain
- Middleware provided through Chain:
pub struct Chain { .. }
impl Handler for Chain { .. }
impl Chain {
fn new<H: Handler>(H) -> Self;
fn link_before<B: BeforeMiddleware>(&mut self, before: B);
fn link_after<A: AfterMiddleware>(&mut self, after: A);
fn around<A: AroundMiddleware>(&mut self, around: A);
}
No magic! Chain could be a third-party type.
Jonathan Reem Iron
Middleware
- Three Kinds:
- BeforeMiddleware
- AfterMiddleware
- AroundMiddleware
Jonathan Reem Iron
BeforeMiddleware
pub trait BeforeMiddleware {
fn before(&self, &mut Request) -> IronResult<()>;
fn catch(&self, _: &mut Request,
err: IronError) -> IronResult<()> { Err(err) }
}
- Run before the Handler
- Only have access to the Request
- Can respond to errors in other BM
Jonathan Reem Iron
AfterMiddleware
pub trait AfterMiddleware {
fn after(&self, &mut Request, Response) -> IronResult<Response>;
fn catch(&self, _: &mut Request,
err: IronError) -> IronResult<()> { Err(err) }
}
- Run after the Handler
- Have access to both Request and Response
- Can respond to all errors
Jonathan Reem Iron
AroundMiddleware
pub trait AfterMiddleware {
fn around(self, handler: Box<Handler>) -> Box<Handler>;
}
- `around` is called immediately
- Used to wrap or modify the Handler in a Chain
- Lets you add arbitrary "control flow"
Jonathan Reem Iron
Plugins and .extensions
- Contain TypeMap, a reflection-based heterogenous key-value store
- Can store arbitrary typed data
- Keys are types
- Used to extend Request and Response
{Request, Response}.extensions:
Iron
By Jonathan Reem
Iron
- 1,342