Skip to main content

middleware_fn

Attribute Macro middleware_fn 

Source
#[middleware_fn]
Expand description

Attribute macro for defining middleware functions with automatic signature injection.

This macro eliminates boilerplate by automatically providing req, res, and ctx parameters to your middleware function. It transforms a simple function into a proper Feather middleware.

§What This Macro Does

The #[middleware_fn] macro injects three parameters into your function:

  • req: &mut Request - The HTTP request
  • res: &mut Response - The HTTP response
  • ctx: &AppContext - Application context for accessing state

Your function must return Outcome (which is Result<MiddlewareResult, Box<dyn Error>>).

§Basic Example

use feather::middleware_fn;

#[middleware_fn]
fn log_requests() {
    println!("{} {}", req.method, req.uri);
    next!()
}

app.use_middleware(log_requests);

§With Route Handlers

use feather::{App, middleware_fn};

#[middleware_fn]
fn greet() {
    let name = req.param("name").unwrap_or("Guest".to_string());
    res.send_text(format!("Hello, {}!", name));
    next!()
}

let mut app = App::new();
app.get("/greet/:name", greet);

§Compared to the middleware! Macro

Both #[middleware_fn] and middleware! work similarly, but #[middleware_fn] is best for reusable, named middleware functions, while middleware! is best for inline closures:

// Using #[middleware_fn] - for reusable middleware
#[middleware_fn]
fn validate_auth() {
    if !req.headers.contains_key("Authorization") {
        res.set_status(401);
        res.send_text("Unauthorized");
        return next!();
    }
    next!()
}

app.use_middleware(validate_auth);

// Using middleware! - for inline middleware
app.get("/", middleware!(|_req, res, _ctx| {
    res.send_text("Hello!");
    next!()
}));

§Accessing Application State

use feather::{State, middleware_fn};

#[derive(Clone)]
struct Config {
    api_key: String,
}

#[middleware_fn]
fn check_api_key() {
    let config = ctx.get_state::<State<Config>>();
    let is_valid = config.with_scope(|cfg| cfg.api_key == "secret");
     
    if !is_valid {
        res.set_status(403);
        res.send_text("Forbidden");
        return next!();
    }
    next!()
}

§Error Handling

use feather::middleware_fn;

#[middleware_fn]
fn parse_json() {
    if let Ok(body) = String::from_utf8(req.body.clone()) {
        // Process body
        next!()
    } else {
        res.set_status(400);
        res.send_text("Invalid UTF-8");
        next!()
    }
}

§See Also

  • Use #[jwt_required] together with #[middleware_fn] for JWT-protected routes
  • See the Middlewares Guide for more patterns