Overview
6 min read
In Node.js you reach for Express, NestJS, or Fastify and trust the framework to wire up routing, body parsing, and middleware. Rust’s web story keeps that same shape but moves the guarantees into the type system: Axum — built on the Tokio async runtime and the Tower middleware ecosystem — turns request inputs into typed extractors, responses into anything that implements IntoResponse, and middleware into composable layers. This section takes you from a one-route hello-server to a production-flavored JSON API with shared state, validation, typed error handling, CORS, JWT authentication, sessions, WebSockets, Server-Sent Events, multipart uploads, static files, and a Dockerized deployment.
Every example targets axum 0.8 (current stable 0.8.9): servers are started with axum::serve(listener, app) over a tokio::net::TcpListener (the removed Server::bind().serve() builder is gone), and path parameters use {id} brace syntax (the old :id colon form was dropped in 0.8). The toolchain throughout is Rust 1.96.0 on the latest stable edition (2024), which cargo new selects automatically.
What You’ll Learn
Section titled “What You’ll Learn”- How the Express mental model — router, handlers,
(req, res), middleware — maps onto Axum’sRouter, asyncfnhandlers, extractors, and Tower layers - How to choose between Axum, Actix Web, and Rocket the way you’d choose between Express, NestJS, and Fastify
- How to set up a Tokio + Axum project and run a server with
axum::serveandtokio::net::TcpListener - Routing: path params (
{id}— never:idin 0.8), query strings, method routing, nested routers, and fallbacks - Extractors (
Path,Query,Json,State, headers), howFromRequest/FromRequestPartswork, and why extractor ordering matters - Middleware as Tower layers:
tower-http(TraceLayer,CorsLayer, compression) and customfrom_fnmiddleware - Shared application state with
State<T>andArc, when to reach for request extensions, and injecting a DB pool or config - Building JSON REST APIs with Serde and the
Jsonextractor/response, including a full CRUD resource - Request validation and returning helpful
400 Bad Requestresponses - Typed error handling with a custom
AppErrorthat implementsIntoResponse, backed bythiserror - CORS, authentication (extractor-as-guard and middleware), JWT, and cookie/server-side sessions
- Real-time features: WebSockets and Server-Sent Events
- Multipart file uploads, serving static files with an SPA fallback, and deploying with a multi-stage Docker build
Topics
Section titled “Topics”| Topic | Description |
|---|---|
| Framework Comparison | Axum vs Actix Web vs Rocket (vs Express/NestJS): tradeoffs and when to pick which. |
| Axum Basics | Express.js → Axum fundamentals: Router, handlers, async fn handlers, running with axum::serve + tokio::net::TcpListener (0.8). |
| Axum Setup | Setting up an Axum project: tokio + axum deps/features, project layout, and a compile-verified hello-server. |
| Routing | Route handlers, path params ({id} in 0.8 — not :id), query params, method routing, nested routers, and fallback. |
| Extractors | Request extractors: Path, Query, Json, State, headers; how FromRequest/FromRequestParts work; extractor ordering. |
| Middleware | Express middleware → Tower/Axum layers; tower-http (TraceLayer, CorsLayer, compression); from_fn middleware. |
| State Management | Shared application state with State<T> + Arc; when to use extensions; injecting a DB pool or config. |
| Request and Response | Request/response handling; IntoResponse; status codes; setting headers; (StatusCode, Json) tuples. |
| JSON APIs | Building JSON REST APIs with Serde and the Json extractor/response; a small CRUD resource. |
| Validation | Request validation (the validator crate and/or manual) and returning 400s with helpful messages. |
| Error Handling | Error handling in handlers: a custom AppError implementing IntoResponse, thiserror, mapping errors to status codes. |
| CORS | CORS configuration with tower-http CorsLayer; permissive vs locked-down. |
| Authentication | Authentication patterns: extractor-as-guard, middleware auth, an AuthUser extractor. |
| JWT | JWT authentication with the jsonwebtoken crate: encoding/decoding, Claims, expiry, verifying in an extractor. |
| Sessions | Session management: cookies, server-side sessions (tower-sessions), and CSRF considerations. |
| WebSockets | WebSocket support with axum::extract::ws: upgrade, send/receive loop, echo server. |
| Server-Sent Events | Server-Sent Events with axum::response::Sse and a Stream of events. |
| File Uploads | Handling multipart file uploads (axum Multipart); streaming to disk. |
| Static Files | Serving static files with tower-http ServeDir/ServeFile; SPA fallback. |
| Deployment | Deploying Axum apps: release builds, multi-stage Docker, binding 0.0.0.0, reverse proxy, and env config. |
Learning Objectives
Section titled “Learning Objectives”By the end of this section, you will be able to:
- Explain how Axum’s router-plus-handlers model corresponds to Express, and where the analogy breaks down (extractors instead of
req,IntoResponseinstead ofres, lazy futures that need a runtime) - Choose a Rust web framework deliberately based on philosophy, ecosystem fit, and team experience
- Stand up an Axum project from scratch and serve it with
axum::serve+tokio::net::TcpListener - Define routes with path and query parameters, method routing, nested routers, and fallbacks using current 0.8 syntax
- Pull typed inputs out of requests with the standard extractors and reason about why ordering matters
- Compose cross-cutting concerns as Tower layers and write custom middleware with
from_fn - Share a database pool, configuration, or in-memory store across handlers with
State<T>andArc - Build a complete JSON CRUD resource that validates input, returns correct status codes, and maps errors to responses through a single
AppError - Add CORS, JWT-based and middleware-based authentication, and cookie/server-side sessions
- Implement real-time endpoints with WebSockets and Server-Sent Events, accept file uploads, serve static assets, and ship the result in a Docker container
Prerequisites
Section titled “Prerequisites”- Section 11: Async Programming — Axum is built on Tokio. Handlers are
async fns, the server is started inside#[tokio::main], and Rust futures are lazy and need a runtime to drive them. The async vocabulary from Section 11 is assumed throughout. - Section 15: Serialization — request bodies and JSON responses ride on Serde. The
Jsonextractor deserializes withDeserializeand theJsonresponse serializes withSerialize, so the derive macros and attributes from Section 15 carry over directly. - Helpful but not required: Section 08: Error Handling — the
AppError/thiserror/?pattern in Error Handling builds on that section’s error vocabulary.
Estimated Time
Section titled “Estimated Time”- Reading: 8-9 hours
- Hands-on Practice: 6-7 hours
- Exercises: 4 hours
- Total: 18-20 hours
Tip: Read Framework Comparison → Axum Basics → Axum Setup → Routing → Extractors as one connected track — that gives you a working server and the core request model. Then State Management, Request and Response, JSON APIs, Validation, and Error Handling compose into a real API. Treat Middleware, CORS, Authentication, JWT, Sessions, WebSockets, Server-Sent Events, File Uploads, Static Files, and Deployment as a toolbox to pull from as each need arises.
Next: Section 17: Database → — connecting your Axum API to PostgreSQL, SQLite, MongoDB, and Redis with SQLx, Diesel, and SeaORM, including the connection pool you’ll inject via State.