Fitrian Musya

Back to Home
RustBackendAPIAxum

Building High-Performance APIs with Axum

4mo ago12 min read
Building High-Performance APIs with Axum

Introduction

Axum is an ergonomic and modular web framework built with Tokio, Tower, and Hyper. It's designed to be easy to use while retaining high performance.

High Level Features

Axum stands out with its clean, macro-free API and strong ecosystem integration:

Macro-free API: Route requests to handlers without complex macros.

Extractors: Declaratively parse requests (JSON, Query, Path) using function signatures.

Tower Ecosystem: Takes full advantage of [tower](https://crates.io/crates/tower) and [tower-http](https://crates.io/crates/tower-http) for middleware, services, and utilities.

Safe Rust: implemented with #![forbid(unsafe_code)] for 100% safe Rust.

Getting Started

First, create a new project and add dependencies:

bash
$cargo new my-axum-app
$cd my-axum-app
$cargo add axum tokio serde serde_json tracing tracing-subscriber

Basic Usage

Here is a simple example showing routing, JSON handling, and starting the server using valid Axum 0.7+ syntax:

rust
use axum::{
routing::{get, post},
http::StatusCode,
Json, Router,
};
use serde::{Deserialize, Serialize};
#[tokio::main]
async fn main() {
// initialize tracing
tracing_subscriber::fmt::init();
// build our application with a route
let app = Router::new()
.route("/", get(root))
.route("/users", post(create_user));
// run our app with hyper, listening globally on port 3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("Listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
// basic handler that responds with a static string
async fn root() -> &'static str {
"Hello, World!"
}
async fn create_user(
// this argument tells axum to parse the request body
// as JSON into a `CreateUser` type
Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
// insert your application logic here
let user = User {
id: 1337,
username: payload.username,
};
// this will be converted into a JSON response
// with a status code of `201 Created`
(StatusCode::CREATED, Json(user))
}
// the input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
username: String,
}
// the output to our `create_user` handler
#[derive(Serialize)]
struct User {
id: u64,
username: String,
}

Why Choose Axum?

1. Performance

Axum is a relatively thin layer on top of Hyper, adding very little overhead. Its performance is comparable to Hyper directly, making it one of the fastest web frameworks available.

2. Ecosystem

Because it implements tower::Service, you get access to a massive ecosystem of middleware for timeout, tracing, compression, and authorization "for free".

3. Reliability

Axum's strict type system and "fearless concurrency" via Rust ensure that many classes of bugs are caught at compile time.

Conclusion

If you are building a backend in Rust, Axum provides the best balance of ergonomics, performance, and ecosystem support today.

Fitrian Musya