Building a Modern API with Axum, Tokio using Rust Programming Language
Published 2026-03-30 15:28:24 · 35 views
Introduction
In recent years, Rust has gained massive popularity for backend development due to its performance, safety, and concurrency guarantees. Among the web frameworks in Rust, Axum stands out for its simplicity, type safety, and strong ecosystem integration.
In this article, we’ll explore how to build a clean, production-ready API using Axum 0.8., and why it’s becoming a preferred choice for modern backend systems.
Why Choose Axum?
Axum is built on top of:
hyper(HTTP engine)tower(middleware and service abstraction)
Key Advantages
Type-safe request handling
Composable routing
Built-in async support
Excellent performance
Seamless integration with the Rust ecosystem
Project Setup
First, create a new Rust project:
cargo new axum-api
cd axum-api
Add dependencies in Cargo.toml:
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"Basic API Structure
Here’s a minimal API server:
use axum::{
routing::{get, post},
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Serialize)]
struct HealthResponse {
status: String,
}
async fn health_check() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".to_string(),
})
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/health", get(health_check));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server running on {}", addr);
axum::serve(tokio::net::TcpListener::bind(addr).await.unwrap(), app)
.await
.unwrap();
}
Request Handling with JSON
Define request and response models:
#[derive(Deserialize)]
struct CreateUser {
name: String,
}
#[derive(Serialize)]
struct UserResponse {
id: u64,
name: String,
}
Handler:
async fn create_user(Json(payload): Json<CreateUser>) -> Json<UserResponse> {
Json(UserResponse {
id: 1,
name: payload.name,
})
}
Add route:
.route("/users", post(create_user))
Extractors: The Power of Axum
Axum uses extractors to parse incoming requests:
Json<T>→ JSON bodyPath<T>→ URL paramsQuery<T>→ query stringState<T>→ shared app state
Example:
use axum::extract::Path;
async fn get_user(Path(id): Path<u64>) -> String {
format!("User ID: {}", id)
}
Application State
In production, you’ll need shared state like DB connections.
use std::sync::Arc;
#[derive(Clone)]
struct AppState {
app_name: String,
}
let state = Arc::new(AppState {
app_name: "My API".into(),
});
let app = Router::new()
.route("/", get(handler))
.with_state(state);
Middleware (Tower Layer)
Axum leverages tower for middleware:
use tower_http::trace::TraceLayer;
let app = Router::new()
.route("/", get(handler))
.layer(TraceLayer::new_for_http());
Common middleware:
Logging
Authentication
Rate limiting
CORS
Error Handling
Custom error handling improves API quality:
use axum::{http::StatusCode, response::IntoResponse};
async fn handler() -> Result<String, StatusCode> {
Err(StatusCode::NOT_FOUND)
}
You can also define custom error types by implementing IntoResponse.
Production Best Practices
1. Structured Project Layout
src/
├── main.rs
├── routes/
├── handlers/
├── models/
├── services/
└── state/
2. Use Environment Config
Use dotenv or config crate for:
DB URLs
API keys
environment configs
3. Logging & Observability
Use:
tracingtower-http
4. Database Integration
Common choices:
sqlx(async, compile-time checked)diesel(ORM)
5. Validation
Use crates like:
validatorserdecustom validation
Performance & Scalability
Axum benefits from:
Rust’s zero-cost abstractions
async runtime (
tokio)no GC pauses
👉 Ideal for:
high-throughput APIs
microservices
real-time systems
When to Use Axum
Choose Axum if you want:
Strong type safety
High performance
Control over architecture
Modern async Rust stack
Conclusion
Axum 0.8. provides a clean, powerful, and scalable way to build APIs in Rust. While it has a learning curve (especially around ownership and async), the payoff is a highly reliable and performant system.
If you’re building modern backend systems and care about safety + performance, Axum is a strong choice.