Skip to content

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.


  • How the Express mental model — router, handlers, (req, res), middleware — maps onto Axum’s Router, async fn handlers, 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::serve and tokio::net::TcpListener
  • Routing: path params ({id} — never :id in 0.8), query strings, method routing, nested routers, and fallbacks
  • Extractors (Path, Query, Json, State, headers), how FromRequest/FromRequestParts work, and why extractor ordering matters
  • Middleware as Tower layers: tower-http (TraceLayer, CorsLayer, compression) and custom from_fn middleware
  • Shared application state with State<T> and Arc, when to reach for request extensions, and injecting a DB pool or config
  • Building JSON REST APIs with Serde and the Json extractor/response, including a full CRUD resource
  • Request validation and returning helpful 400 Bad Request responses
  • Typed error handling with a custom AppError that implements IntoResponse, backed by thiserror
  • 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

TopicDescription
Framework ComparisonAxum vs Actix Web vs Rocket (vs Express/NestJS): tradeoffs and when to pick which.
Axum BasicsExpress.js → Axum fundamentals: Router, handlers, async fn handlers, running with axum::serve + tokio::net::TcpListener (0.8).
Axum SetupSetting up an Axum project: tokio + axum deps/features, project layout, and a compile-verified hello-server.
RoutingRoute handlers, path params ({id} in 0.8 — not :id), query params, method routing, nested routers, and fallback.
ExtractorsRequest extractors: Path, Query, Json, State, headers; how FromRequest/FromRequestParts work; extractor ordering.
MiddlewareExpress middleware → Tower/Axum layers; tower-http (TraceLayer, CorsLayer, compression); from_fn middleware.
State ManagementShared application state with State<T> + Arc; when to use extensions; injecting a DB pool or config.
Request and ResponseRequest/response handling; IntoResponse; status codes; setting headers; (StatusCode, Json) tuples.
JSON APIsBuilding JSON REST APIs with Serde and the Json extractor/response; a small CRUD resource.
ValidationRequest validation (the validator crate and/or manual) and returning 400s with helpful messages.
Error HandlingError handling in handlers: a custom AppError implementing IntoResponse, thiserror, mapping errors to status codes.
CORSCORS configuration with tower-http CorsLayer; permissive vs locked-down.
AuthenticationAuthentication patterns: extractor-as-guard, middleware auth, an AuthUser extractor.
JWTJWT authentication with the jsonwebtoken crate: encoding/decoding, Claims, expiry, verifying in an extractor.
SessionsSession management: cookies, server-side sessions (tower-sessions), and CSRF considerations.
WebSocketsWebSocket support with axum::extract::ws: upgrade, send/receive loop, echo server.
Server-Sent EventsServer-Sent Events with axum::response::Sse and a Stream of events.
File UploadsHandling multipart file uploads (axum Multipart); streaming to disk.
Static FilesServing static files with tower-http ServeDir/ServeFile; SPA fallback.
DeploymentDeploying Axum apps: release builds, multi-stage Docker, binding 0.0.0.0, reverse proxy, and env config.

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, IntoResponse instead of res, 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> and Arc
  • 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

  • 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 Json extractor deserializes with Deserialize and the Json response serializes with Serialize, 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.

  • Reading: 8-9 hours
  • Hands-on Practice: 6-7 hours
  • Exercises: 4 hours
  • Total: 18-20 hours

Tip: Read Framework ComparisonAxum BasicsAxum SetupRoutingExtractors 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.