Expand description
§axum_folder_router Macro Documentation
folder_router! is a procedural macro for the Axum web framework that automatically generates router boilerplate based on your file structure. It simplifies route organization by using filesystem conventions to define your API routes.
§Installation
Add the dependency to your Cargo.toml:
[dependencies]
axum_folder_router = "0.1.0"
axum = "0.7"§Basic Usage
The macro scans a directory for route.rs files and automatically creates an Axum router based on the file structure:
use anyhow;
use axum::Router;
use axum_folder_router::folder_router;
use tokio;
#[derive(Clone, Debug)]
struct AppState {
_foo: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create app state
let app_state = AppState {
_foo: "".to_string(),
};
// Generate the router using the macro
let folder_router: Router<AppState> = folder_router!("./examples/simple/api", AppState);
// Build the router and provide the state
let app: Router<()> = folder_router.with_state(app_state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
println!("Listening on http://{}", listener.local_addr()?);
axum::serve(listener, app).await?;
Ok(())
}§File Structure Convention
The macro converts your file structure into routes:
src/api/
├── route.rs -> "/"
├── hello/
│ └── route.rs -> "/hello"
├── users/
│ ├── route.rs -> "/users"
│ └── [id]/
│ └── route.rs -> "/users/{id}"
└── files/
└── [...path]/
└── route.rs -> "/files/*path"Each route.rs file can contain HTTP method handlers that are automatically mapped to the corresponding route.
§Route Handlers
Inside each route.rs file, define async functions named after HTTP methods:
use axum::response::{Html, IntoResponse};
pub async fn get() -> impl IntoResponse {
Html("<h1>Hello World!</h1>").into_response()
}
pub async fn post() -> impl IntoResponse {
"Posted successfully".into_response()
}
§Supported Features
§HTTP Methods
The macro supports all standard HTTP methods:
getpostputdeletepatchheadoptions
§Path Parameters
Dynamic path segments are defined using brackets:
src/api/users/[id]/route.rs -> "/users/{id}"Inside the route handler:
use axum::{
extract::Path,
response::IntoResponse
};
pub async fn get(Path(id): Path<String>) -> impl IntoResponse {
format!("User ID: {}", id)
}§Catch-all Parameters
Use the spread syntax for catch-all segments:
src/api/files/[...path]/route.rs -> "/files/*path"use axum::{
extract::Path,
response::IntoResponse
};
pub async fn get(Path(path): Path<String>) -> impl IntoResponse {
format!("Requested file path: {}", path)
}§State Extraction
The state type provided to the macro is available in all route handlers:
use axum::{
extract::State,
response::IntoResponse
};
pub async fn get(State(state): State<AppState>) -> impl IntoResponse {
format!("State: {:?}", state)
}§Limitations
- Compile-time Only: The routing is determined at compile time, so dynamic route registration isn’t supported.
- File I/O: The macro performs file I/O during compilation, which may have implications in certain build environments.
- Single State Type: All routes share the same state type, though you can use
FromReffor more granular state extraction.
§Best Practices
- Consistent Structure: Maintain a consistent file structure to make your API organization predictable.
- Individual Route Files: Use one
route.rsfile per route path for clarity. - Module Organization: Consider grouping related functionality in directories.
- Documentation: Add comments to each route handler explaining its purpose.
Macros§
- folder_
router - Creates an Axum router by scanning a directory for
route.rsfiles.