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:listprints 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.