Loading pageâŚ
Rust walkthroughs
Loading pageâŚ
axum::routing::get and MethodRouter::on for HTTP method-specific handler registration?axum::routing::get is a convenience function that creates a MethodRouter pre-configured for the GET method, while MethodRouter::on is a method on an existing MethodRouter that adds a route for a specified HTTP methodâget is for the common case of a single-method route, while on enables method-specific routing on a combined router. The get function creates a fresh MethodRouter that handles only GET requests; on allows you to add handlers for specific methods to an existing router. Under the hood, get(handler) is equivalent to MethodRouter::new().on(Method::GET, handler), but the convenience functions are more ergonomic for the common case of single-method routes.
use axum::{routing::get, Router, handler::Handler;
async fn handle_get() -> &'static str {
"GET response"
}
fn basic_get_route() -> Router {
// Using the convenience function
Router::new().route("/path", get(handle_get))
}The get function creates a MethodRouter that handles GET requests for this route.
use axum::{routing::{get, MethodRouter}, Router, http::Method};
async fn handle_get() -> &'static str {
"GET response"
}
async fn handle_post() -> &'static str {
"POST response"
}
fn using_on() -> Router {
// Using on() with explicit method
Router::new().route("/path",
MethodRouter::new()
.on(Method::GET, handle_get)
.on(Method::POST, handle_post)
)
}
fn equivalent_convenience() -> Router {
// Equivalent using convenience functions
Router::new().route("/path",
get(handle_get).post(handle_post)
)
}on allows specifying the method as a parameter; convenience functions embed the method.
use axum::{routing::MethodRouter, http::Method, handler::Handler;
// The get function is essentially:
fn get_approx<H, T>(handler: H) -> MethodRouter
where
H: Handler<T>,
{
MethodRouter::new().on(Method::GET, handler)
}
// Similarly for post, put, delete, etc.:
fn post_approx<H, T>(handler: H) -> MethodRouter
where
H: Handler<T>,
{
MethodRouter::new().on(Method::POST, handler)
}
// The convenience functions are shortcuts for on()Convenience functions like get wrap MethodRouter::on with the method pre-specified.
use axum::{routing::get, Router, http::Method};
async fn handle_get() -> &'static str { "GET" }
async fn handle_post() -> &'static str { "POST" }
async fn handle_put() -> &'static str { "PUT" }
fn combining_methods() {
// Convenience function chaining
let router1 = Router::new().route("/api",
get(handle_get)
.post(handle_post)
.put(handle_put)
);
// Using on() explicitly
use axum::routing::MethodRouter;
let router2 = Router::new().route("/api",
MethodRouter::new()
.on(Method::GET, handle_get)
.on(Method::POST, handle_post)
.on(Method::PUT, handle_put)
);
// Both are equivalent
}Chaining convenience functions or calling on multiple times both work.
use axum::{routing::{get, MethodRouter}, Router, http::Method};
fn when_to_use_which() {
// Use convenience functions (get, post, etc.) when:
// - Standard HTTP methods
// - Single method per route
// - Code readability is priority
// Single method - use convenience
let single = Router::new().route("/users", get(list_users));
// Multiple methods - chain convenience functions
let multiple = Router::new().route("/users",
get(list_users).post(create_user)
);
// Use on() when:
// - Non-standard HTTP methods
// - Dynamic method selection
// - Building routers programmatically
// Non-standard method
let custom = Router::new().route("/webhook",
MethodRouter::new().on(Method::from_bytes(b"WEBHOOK").unwrap(), handle_webhook)
);
// Dynamic method selection
let methods = vec
![Method::GET, Method::POST];
let mut router = MethodRouter::new();
for method in methods {
router = router.on(method, dynamic_handler);
}
}
async fn list_users() -> &'static str { "users" }
async fn create_user() -> &'static str { "created" }
async fn handle_webhook() -> &'static str { "webhook" }
async fn dynamic_handler() -> &'static str { "dynamic" }Use convenience functions for standard cases; on for flexibility.
use axum::{routing::{get, MethodRouter}, http::Method};
fn method_router_construction() {
// Convenience function creates MethodRouter
let router1: MethodRouter = get(handler);
// on() also returns MethodRouter (builder pattern)
let router2: MethodRouter = MethodRouter::new().on(Method::GET, handler);
// They're the same type
let router3: MethodRouter = get(handler).post(handler);
let router4: MethodRouter = MethodRouter::new()
.on(Method::GET, handler)
.on(Method::POST, handler);
// Both produce identical MethodRouter instances
}
async fn handler() -> &'static str { "ok" }Both approaches produce MethodRouter values that can be used interchangeably.
use axum::routing::{get, post, put, patch, delete, head, options, trace, connect};
fn standard_functions() {
// axum provides convenience functions for standard methods:
// get(handler) -> MethodRouter for GET
// post(handler) -> MethodRouter for POST
// put(handler) -> MethodRouter for PUT
// patch(handler) -> MethodRouter for PATCH
// delete(handler) -> MethodRouter for DELETE
// head(handler) -> MethodRouter for HEAD
// options(handler) -> MethodRouter for OPTIONS
// trace(handler) -> MethodRouter for TRACE
// connect(handler) -> MethodRouter for CONNECT
// These are the common methods; on() covers everything else
}Convenience functions cover standard HTTP methods; on handles any method.
use axum::{routing::MethodRouter, http::Method, Router};
fn dynamic_routing() {
// Build router dynamically based on configuration
let config = vec
![
(Method::GET, list_items as fn() -> &'static str),
(Method::POST, create_item as fn() -> &'static str),
(Method::DELETE, delete_item as fn() -> &'static str),
];
let mut router = MethodRouter::new();
for (method, handler) in config {
router = router.on(method, handler);
}
// This pattern allows runtime configuration of routes
// Can't do this easily with convenience functions:
// The method is embedded in the function name
}
async fn list_items() -> &'static str { "list" }
async fn create_item() -> &'static str { "create" }
async fn delete_item() -> &'static str { "delete" }on enables runtime-determined method routing; convenience functions are compile-time.
use axum::{routing::{get, MethodRouter}, Router, http::Method};
fn method_router_state() {
// MethodRouter tracks:
// 1. Which methods have handlers
// 2. The handlers for each method
// 3. Any fallback for unhandled methods
// Convenience functions initialize this state
let get_only: MethodRouter = get(handler);
// Only GET is handled
// on() adds to the state
let get_and_post: MethodRouter = MethodRouter::new()
.on(Method::GET, handler)
.on(Method::POST, handler);
// GET and POST are handled
// Chaining adds to existing state
let all_three: MethodRouter = get(handler)
.post(handler)
.put(handler);
// GET, POST, PUT handled
}
async fn handler() -> &'static str { "ok" }MethodRouter accumulates method-handler pairs; both approaches add to this state.
use axum::{routing::{get, MethodRouter}, Router, http::StatusCode};
fn fallback_behavior() {
// Unhandled methods return 405 Method Not Allowed
// This applies to both approaches:
let router = Router::new().route("/path", get(handler));
// POST /path -> 405 Method Not Allowed
let router = Router::new().route("/path",
MethodRouter::new().on(axum::http::Method::GET, handler)
);
// POST /path -> 405 Method Not Allowed (same behavior)
// Can add fallback handler:
let router = Router::new().route("/path",
get(handler).fallback(fallback_handler)
);
}
async fn handler() -> &'static str { "handled" }
async fn fallback_handler() -> (StatusCode, &'static str) {
(StatusCode::METHOD_NOT_ALLOWED, "not allowed")
}Both produce the same 405 behavior for unhandled methods.
use axum::{routing::MethodRouter, http::Method, Router};
fn method_guarding() {
// on() can be used for method validation patterns
// Custom method checking
fn methods_router(
get_handler: fn() -> &'static str,
post_handler: fn() -> &'static str,
) -> MethodRouter {
MethodRouter::new()
.on(Method::GET, get_handler)
.on(Method::POST, post_handler)
}
// Programmatic method filtering
fn safe_methods_only(handler: fn() -> &'static str) -> MethodRouter {
let mut router = MethodRouter::new();
for method in [Method::GET, Method::HEAD, Method::OPTIONS] {
router = router.on(method, handler);
}
router
}
// This pattern is harder with convenience functions
}
async fn generic_handler() -> &'static str { "safe" }on enables programmatic construction of method routing patterns.
use axum::{routing::{get, MethodRouter}, Router, http::Method};
fn composition() {
// Both approaches compose the same way
// Convenience function approach
let api_routes = Router::new()
.route("/users", get(list_users).post(create_user))
.route("/items", get(list_items));
// on() approach
let api_routes = Router::new()
.route("/users",
MethodRouter::new()
.on(Method::GET, list_users)
.on(Method::POST, create_user)
)
.route("/items",
MethodRouter::new().on(Method::GET, list_items)
);
// Both produce equivalent routers
}
async fn list_users() -> &'static str { "users" }
async fn create_user() -> &'static str { "created" }
async fn list_items() -> &'static str { "items" }Both approaches work identically when composing routes.
use axum::{routing::MethodRouter, http::Method};
fn type_signatures() {
// Both produce MethodRouter<_, _, _>
// Convenience functions:
// fn get<H, T, B>(handler: H) -> MethodRouter<_, B, Infallible>
// where H: Handler<T, B>
// on method:
// fn on<H, T, B>(self, method: Method, handler: H) -> MethodRouter<_, B, Infallible>
// where H: Handler<T, B>
// The key difference in signature:
// - get: takes handler, returns new MethodRouter
// - on: takes self + method + handler, returns MethodRouter
// This means:
// - get() creates from scratch
// - on() extends existing (self)
}get creates a new MethodRouter; on extends an existing one.
use axum::{routing::MethodRouter, http::Method, Router};
fn any_method() {
// Method::ANY is not a real HTTP method
// But some frameworks use "any" to match all methods
// In axum, you handle this differently:
// Use .fallback() or specify methods explicitly
// To accept ANY method (including extensions):
let router = Router::new().route("/path",
MethodRouter::new().fallback(any_handler)
);
// Or explicitly list all standard methods:
let router = Router::new().route("/path",
MethodRouter::new()
.on(Method::GET, any_handler)
.on(Method::POST, any_handler)
.on(Method::PUT, any_handler)
// ... etc
);
}
async fn any_handler() -> &'static str { "any method" }axum uses fallback for handling arbitrary methods; on still takes specific methods.
use axum::{routing::get, Router, http::Method, routing::MethodRouter};
fn readability() {
// Convenience functions: clear and concise
let readable = Router::new()
.route("/users", get(list_users).post(create_user))
.route("/items", get(list_items).delete(delete_item));
// on(): more explicit but verbose
let explicit = Router::new()
.route("/users",
MethodRouter::new()
.on(Method::GET, list_users)
.on(Method::POST, create_user)
)
.route("/items",
MethodRouter::new()
.on(Method::GET, list_items)
.on(Method::DELETE, delete_item)
);
// Readable code prefers convenience functions
// Unless there's a specific reason for on()
}
async fn list_users() -> &'static str { "users" }
async fn create_user() -> &'static str { "create" }
async fn list_items() -> &'static str { "items" }
async fn delete_item() -> &'static str { "delete" }Convenience functions are more readable for standard cases.
The relationship:
// get(handler) is essentially:
// MethodRouter::new().on(Method::GET, handler)
// The convenience functions are thin wrappers around on()
// get(handler) <=> MethodRouter::new().on(Method::GET, handler)
// post(handler) <=> MethodRouter::new().on(Method::POST, handler)
// put(handler) <=> MethodRouter::new().on(Method::PUT, handler)
// ... etcWhen to use convenience functions:
// Standard HTTP methods
Router::new().route("/api", get(handler))
Router::new().route("/api", get(get_handler).post(post_handler))
// Multiple standard methods
Router::new().route("/api",
get(get_handler)
.post(post_handler)
.put(put_handler)
.delete(delete_handler)
)
// When readability matters (most cases)When to use on:
// Non-standard HTTP methods
MethodRouter::new().on(Method::from_bytes(b"CUSTOM").unwrap(), handler)
// Dynamic method configuration
let mut router = MethodRouter::new();
for (method, handler) in configured_routes {
router = router.on(method, handler);
}
// When building routers programmatically
// Method::GET is dynamic, not hardcodedKey insight: axum::routing::get is a convenience function that creates a MethodRouter configured for GET requestsâinternally it calls MethodRouter::new().on(Method::GET, handler). The MethodRouter::on method is the underlying mechanism that all convenience functions use. Use convenience functions (get, post, put, delete, etc.) for standard HTTP methods and readable code; use on when you need non-standard methods, dynamic method selection at runtime, or are building routers programmatically. Both approaches produce identical MethodRouter values and compose the same way.