Build status codecov Rust Docs Crate version Download Version License: MIT

Introduction

Roa is an async web framework inspired by koajs, lightweight but powerful.

Application

A Roa application is a structure containing a middleware group which composes and executes middleware functions in a stack-like manner.

The obligatory hello world application:

```rust use roa_core::App; use log::info; use std::error::Error as StdError;

[async_std::main]

async fn main() -> Result<(), Box> { let mut app = App::new(()); app.end(|ctx| async move { ctx.respmut().await.writestr("Hello, World"); Ok(()) }); app.listen("127.0.0.1:8000", |addr| { info!("Server is listening on {}", addr) })? .await?; Ok(()) } ```

Cascading

The following example responds with "Hello World", however, the request flows through the logging middleware to mark when the request started, then continue to yield control through the response middleware. When a middleware invokes next().await the function suspends and passes control to the next middleware defined. After there are no more middleware to execute downstream, the stack will unwind and each middleware is resumed to perform its upstream behaviour.

```rust use roa_core::App; use log::info; use std::error::Error as StdError; use std::time::Instant;

[async_std::main]

async fn main() -> Result<(), Box> { let mut app = App::new(()); app.gatefn(|ctx, next| async move { let inbound = Instant::now(); next().await?; info!("time elapsed: {} ms", inbound.elapsed().as_millis()); Ok(()) });

app.end(|ctx| async move {
    ctx.resp_mut().await.write_str("Hello, World");
    Ok(())
});
app.listen("127.0.0.1:8000", |addr| {
    info!("Server is listening on {}", addr)
})?
.await?;
Ok(())

} ```

Error Handling

You can catch or straightly throw a Error returned by next.

```rust use roacore::{App, throw}; use asyncstd::task::spawn; use http::StatusCode;

[tokio::main]

async fn main() -> Result<(), Box> { let (addr, server) = App::new(()) .gatefn(|ctx, next| async move { // catch if let Err(err) = next().await { // teapot is ok if err.statuscode != StatusCode::IMATEAPOT { return Err(err) } } Ok(()) }) .gatefn(|ctx, next| async move { next().await?; // just throw unreachable!() }) .end(|ctx| async move { throw!(StatusCode::IMATEAPOT, "I'm a teapot!") }) .runlocal()?; spawn(server); let resp = reqwest::get(&format!("http://{}", addr)).await?; asserteq!(StatusCode::OK, resp.status()); Ok(()) } ```

error_handler

App has a errorhandler to handle Error thrown by the top middleware. This is the errorhandler:

rust use roa_core::{Context, Error, Result, Model, ErrorKind}; pub async fn error_handler<M: Model>(context: Context<M>, err: Error) -> Result { context.resp_mut().await.status = err.status_code; if err.expose { context.resp_mut().await.write_str(&err.message); } if err.kind == ErrorKind::ServerError { Err(err) } else { Ok(()) } }

The Error thrown by this error_handler will be handled by hyper.