Routing and Handlers
Express routes vs Axum routes
Section titled “Express routes vs Axum routes”In Express you attach handlers directly to app or a Router. In Axum you build a Router struct by chaining .route() calls. There are no magic strings for HTTP verbs — instead you import functions like get, post, put, delete from axum::routing.
import express from 'express';const router = express.Router();
router.get('/users', listUsers);router.post('/users', createUser);router.get('/users/:id', getUser);router.delete('/users/:id', deleteUser);
export default router;use axum::{ routing::{delete, get, post}, Router,};
use crate::handlers::users::{ create_user, delete_user, get_user, list_users,};
pub fn users_router() -> Router { Router::new() .route("/users", get(list_users).post(create_user)) .route("/users/:id", get(get_user).delete(delete_user))}Writing an async fn handler
Section titled “Writing an async fn handler”An Axum handler is any async fn whose arguments are extractors and whose return type implements IntoResponse. The simplest handler returns a string:
// Expressasync function hello(req, res) { res.send('Hello, World!');}// Axum — returning a plain stringasync fn hello() -> &'static str { "Hello, World!"}impl IntoResponse — return anything
Section titled “impl IntoResponse — return anything”Axum handlers can return many types: &str, String, Json<T>, (StatusCode, Json<T>), or your own custom type as long as it implements IntoResponse.
// Express — manual JSON responseasync function listUsers(req, res) { const users = [{ id: 1, name: 'Alice' }]; res.status(200).json(users);}use axum::{http::StatusCode, Json};use serde::Serialize;
#[derive(Serialize)]struct User { id: u32, name: String,}
async fn list_users() -> (StatusCode, Json<Vec<User>>) { let users = vec![User { id: 1, name: "Alice".to_string() }]; (StatusCode::OK, Json(users))}Nested routers and mounting
Section titled “Nested routers and mounting”Just like Express lets you mount sub-routers at a prefix, Axum supports Router::nest:
// Expressimport userRouter from './users.router';app.use('/api/v1', userRouter);use axum::Router;
pub fn create_router() -> Router { Router::new() .nest("/api/v1", users_router()) .nest("/api/v1", health_router())}Run locally — handlers need a running Axum server. Use
cargo runto start the server, thencurl http://localhost:3000/usersto test.