Skip to content
C Codeloom
Rust

Rust Axum Web Framework Tutorial

A practical introduction to building HTTP services in Rust using the Axum web framework, with routing, extractors, state, and JSON handling.

·4 min read · By Codeloom
Intermediate 9 min read

What you'll learn

  • Core concept introduced
  • How the API is structured
  • Typical idiomatic usage
  • Common pitfalls to avoid
  • When and where to apply it

Prerequisites

  • Basic Rust familiarity

What and Why

Axum is a web framework for Rust built on top of tokio, hyper, and tower. It uses Rust’s type system to make routing and request handling feel ergonomic without sacrificing performance. Unlike older Rust frameworks that relied on heavy macros, Axum models handlers as plain async functions whose parameters are “extractors” - types that know how to pull data out of a request.

The “why” is straightforward. You get the speed and safety of Rust, native async I/O via Tokio, and a middleware ecosystem (the entire tower stack) shared with other Rust services like gRPC servers. That means your authentication layer, retries, timeouts, and tracing can be reused across protocols.

Mental Model

Axum has three core abstractions you should hold in your head: a Router that maps paths and methods to handlers, handlers that are async functions whose arguments implement FromRequestParts or FromRequest, and a return type that implements IntoResponse. Shared application data flows through State<T>, while request-scoped data flows through extractors like Path, Query, Json, and Extension.

If you think of a handler as (extracted inputs) -> impl IntoResponse, most of Axum clicks into place. The compiler enforces correctness: if you ask for Json<MyDto>, deserialization happens before your code runs, and a deserialization failure becomes a 400 response automatically.

Hands-on Example

Here is a minimal Axum app that exposes a JSON endpoint and uses shared state.

use axum::{extract::State, routing::get, Json, Router};
use serde::Serialize;
use std::sync::Arc;

#[derive(Clone)]
struct AppState { greeting: String }

#[derive(Serialize)]
struct Hello { message: String }

async fn hello(State(s): State<Arc<AppState>>) -> Json<Hello> {
    Json(Hello { message: s.greeting.clone() })
}

#[tokio::main]
async fn main() {
    let state = Arc::new(AppState { greeting: "hi".into() });
    let app = Router::new()
        .route("/hello", get(hello))
        .with_state(state);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
Axum request flow from socket to handler

The diagram shows how a byte stream becomes a typed handler call and turns back into bytes on the way out.

Common Pitfalls

The biggest pitfall newcomers hit is extractor ordering. Extractors that consume the body (like Json or Form) must come last, because only one extractor can read the body. Putting Json<T> before Path<U> will fail to compile with a confusing error.

Another trap is State versus Extension. State is type-checked at compile time and tied to the router; Extension is dynamic and resolved at runtime. Prefer State unless you genuinely need runtime-injected dependencies.

Finally, watch your error types. Returning Result<T, E> only works when E: IntoResponse. Many devs wrap errors in a custom AppError newtype to satisfy that bound.

Practical Tips

Use tower-http for tracing, CORS, and compression instead of writing your own middleware. Add #[tokio::main(flavor = "multi_thread")] for CPU-bound workloads, but the default is fine for I/O. When testing, build a Router and call it directly with tower::ServiceExt::oneshot - no network needed. Group routes with Router::nest to keep large apps tidy, and prefer axum::extract::FromRequestParts for custom extractors that don’t consume the body.

Wrap-up

Axum gives Rust developers a clean, type-driven path to writing web services. Lean on extractors, return impl IntoResponse, share state through State<T>, and reach for tower middleware before writing your own. Once the mental model clicks, you’ll find Axum apps surprisingly small and pleasant to maintain.