Routes are typed, and so is their middleware.

Routes, groups, names and constraints in the shape you would expect — with middleware attached as values the compiler checks, rather than strings a map resolves at runtime.

What you get

  • Named routes and a URL generator: Url::instance().absolute("api.posts.show", …).
  • Groups with a prefix, a name prefix and a middleware stack, nested as deep as you like.
  • Constraints that 404 before your handler runs: where_slug, where_number, where_uuid, where_in.
  • Extractors say what an action needs: Req, Validated<T>, Bound<Post>, AuthenticatedUser<User>, Json<T>, Path<T>.
  • Middleware attached by value — a misspelt or deleted middleware is a compile error naming every route that used it.
  • route:list prints the table the router actually compiled.

In the docs

src/routes/api.rs
use rainier_framework::prelude::*;

use crate::app::http::controllers::post_controller;
use crate::app::http::kernel;

pub fn routes(router: &mut Router) {
    router.group(
        GroupAttributes::new().prefix("api").name("api.").middleware(kernel::api()),
        |router| {
            router.get("/posts", post_controller::index).name("posts.index");
            router
                .get("/posts/{post}", post_controller::show)
                .name("posts.show")
                .where_slug("post");

            router.group(GroupAttributes::new().middleware(kernel::auth("api")), |router| {
                router.post("/posts", post_controller::store).name("posts.store");
            });
        },
    );
}
src/app/http/kernel.rs
/// A group is a function returning a stack — not a name in a map.
pub fn web() -> MiddlewareStack {
    groups::web().with(RequireApiKey)
}

// Middleware is attached by value. A typo is a compile error, and so is
// renaming it: every route that used the old name is listed, by file.
router
    .get("/me", me)
    .middleware(Authenticate::<User>::resolved_with_guard("api"));

// The string version, `->middleware('athu')`, boots — and serves the
// route unguarded.

Up close

Select an image to see it full size.

Middleware is attached by value, so naming it by string does not compile: rustc refuses .middleware("auth") and lists the middleware types that would work.
route:list shows the middleware each route actually runs, so the routes behind Authenticate are visible at a glance.
A group takes its middleware from a function call, so renaming the stack in the kernel breaks this line at compile time instead of at runtime.
All features

Type to search 2.0.0 docs.