Routing
Ferro provides an expressive routing API similar to Laravel.
Basic Routes
Define routes in src/routes.rs:
#![allow(unused)] fn main() { use ferro::*; pub fn routes() -> Router { Router::new() .get("/", home) .get("/users", users::index) .post("/users", users::store) .put("/users/:id", users::update) .delete("/users/:id", users::destroy) } }
Route Parameters
Parameters are extracted from the URL path:
#![allow(unused)] fn main() { #[handler] pub async fn show(req: Request, id: i64) -> Response { // id is extracted from /users/:id let user = User::find_by_id(id).one(&db).await?; Ok(json!(user)) } }
Optional Parameters
Use Option<T> for optional parameters:
#![allow(unused)] fn main() { #[handler] pub async fn index(req: Request, page: Option<i64>) -> Response { let page = page.unwrap_or(1); // ... } }
Route Groups
Group routes with shared middleware or prefixes:
#![allow(unused)] fn main() { pub fn routes() -> Router { Router::new() .group("/api", |group| { group .get("/users", api::users::index) .post("/users", api::users::store) .middleware(ApiAuthMiddleware) }) .group("/admin", |group| { group .get("/dashboard", admin::dashboard) .middleware(AdminMiddleware) }) } }
Named Routes
#![allow(unused)] fn main() { Router::new() .get("/users/:id", users::show).name("users.show") }
Generate URLs:
#![allow(unused)] fn main() { let url = route("users.show", [("id", "1")]); // => "/users/1" }
Resource Routes
Generate CRUD routes for a resource:
#![allow(unused)] fn main() { Router::new() .resource("/users", users_controller) }
This creates:
| Method | URI | Handler |
|---|---|---|
| GET | /users | index |
| GET | /users/create | create |
| POST | /users | store |
| GET | /users/:id | show |
| GET | /users/:id/edit | edit |
| PUT | /users/:id | update |
| DELETE | /users/:id | destroy |
Route Middleware
Apply middleware to specific routes:
#![allow(unused)] fn main() { Router::new() .get("/dashboard", dashboard) .middleware(AuthMiddleware) }
Or to groups:
#![allow(unused)] fn main() { Router::new() .group("/admin", |group| { group .get("/users", admin::users) .middleware(AdminMiddleware) }) }
Fallback Routes
Handle 404s:
#![allow(unused)] fn main() { Router::new() .get("/", home) .fallback(not_found) }
Route Constraints
Validate route parameters:
#![allow(unused)] fn main() { Router::new() .get("/users/:id", users::show) .where_("id", r"\d+") // Must be numeric }
API Routes
For JSON APIs, typically group under /api:
#![allow(unused)] fn main() { Router::new() .group("/api/v1", |api| { api .get("/users", api::users::index) .post("/users", api::users::store) .middleware(ApiAuthMiddleware) }) }
View Routes
For simple views without controller logic:
#![allow(unused)] fn main() { Router::new() .view("/about", "About", AboutProps::default()) }
Redirect Routes
#![allow(unused)] fn main() { Router::new() .redirect("/old-path", "/new-path") .redirect_permanent("/legacy", "/modern") }
Route Caching
In production, routes are compiled at build time for optimal performance.