[][src]Type Definition roa_core::Next

type Next = Box<dyn FnOnce() -> ResultFuture + Sync + Send>;

Type of the second parameter in a middleware.

Next is usually a closure capturing the next middleware, context and the next Next.

Developer of middleware can jump to next middleware by calling next().await.

Example

use roa_core::App;
use async_std::task::spawn;
use http::StatusCode;

struct Symbol;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (addr, server) = App::new(())
        .gate_fn(|ctx, next| async move {
            ctx.store::<Symbol>("id", "1".to_string()).await;
            next().await?;
            assert_eq!("5", ctx.load::<Symbol>("id").await.unwrap().as_ref());
            Ok(())
        })
        .gate_fn(|ctx, next| async move {
            assert_eq!("1", ctx.load::<Symbol>("id").await.unwrap().as_ref());
            ctx.store::<Symbol>("id", "2".to_string()).await;
            next().await?;
            assert_eq!("4", ctx.load::<Symbol>("id").await.unwrap().as_ref());
            ctx.store::<Symbol>("id", "5".to_string()).await;
            Ok(())
        })
        .gate_fn(|ctx, next| async move {
            assert_eq!("2", ctx.load::<Symbol>("id").await.unwrap().as_ref());
            ctx.store::<Symbol>("id", "3".to_string()).await;
            next().await?; // next is none; do nothing
            assert_eq!("3", ctx.load::<Symbol>("id").await.unwrap().as_ref());
            ctx.store::<Symbol>("id", "4".to_string()).await;
            Ok(())
        })
        .run_local()?;
    spawn(server);
    let resp = reqwest::get(&format!("http://{}", addr)).await?;
    assert_eq!(StatusCode::OK, resp.status());
    Ok(())
}

Error Handling

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

use roa_core::{App, throw};
use async_std::task::spawn;
use http::StatusCode;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (addr, server) = App::new(())
        .gate_fn(|ctx, next| async move {
            // catch
            if let Err(err) = next().await {
                // teapot is ok
                if err.status_code != StatusCode::IM_A_TEAPOT {
                    return Err(err);
                }
            }
            Ok(())
        })
        .gate_fn(|ctx, next| async move {
            next().await?; // just throw
            unreachable!()
        })
        .gate_fn(|_ctx, _next| async move {
            throw!(StatusCode::IM_A_TEAPOT, "I'm a teapot!")
        })
        .run_local()?;
    spawn(server);
    let resp = reqwest::get(&format!("http://{}", addr)).await?;
    assert_eq!(StatusCode::OK, resp.status());
    Ok(())
}