DEV Community

Syeed Talha
Syeed Talha

Posted on

Understand Your First Axum Server by Comparing with FastAPI

If you're coming from Python and have used FastAPI, learning Rust’s Axum can feel confusing at first. But the good news is: the core ideas are almost the same.

Let’s break down this simple Axum server step by step and compare it with FastAPI so it clicks instantly.


🧩 The Full Code

use axum::{ routing::get, Router, };
use std::net::SocketAddr;

#[tokio::main]
async fn main() {
    // 1. Create a route
    let app = Router::new()
        .route("/", get(root));

    // 2. Define address
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    println!("Server running at http://{}", addr);

    // 3. Run server
    let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

// 4. Handler function
async fn root() -> &'static str {
    "Hello, Axum! Hello guys how are you!!!"
}
Enter fullscreen mode Exit fullscreen mode

🧠 Big Picture

This program does 4 simple things:

  1. Create a web app
  2. Define a route (/)
  3. Start a server on 127.0.0.1:3000
  4. Return a response when someone visits

🔹 Step 1: Importing Things

use axum::{ routing::get, Router };
use std::net::SocketAddr;
Enter fullscreen mode Exit fullscreen mode

What this means:

  • Bring Router → to create the app
  • Bring get → to define GET routes
  • Bring SocketAddr → to define IP + port

🐍 FastAPI equivalent:

from fastapi import FastAPI
Enter fullscreen mode Exit fullscreen mode

🔹 Step 2: Async Main Function

#[tokio::main]
async fn main() {
Enter fullscreen mode Exit fullscreen mode

What this means:

Rust normally doesn’t support async in main, so we use Tokio (an async runtime).

👉 This is like saying:

“Run this program using async engine”

🐍 FastAPI equivalent:

import asyncio

async def main():
    ...

asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

🔹 Step 3: Create the App

let app = Router::new()
    .route("/", get(root));
Enter fullscreen mode Exit fullscreen mode

What this means:

  • Create a new app (Router::new())
  • Add a route /
  • When someone sends a GET request, call root

🐍 FastAPI equivalent:

app = FastAPI()

@app.get("/")
async def root():
    return "Hello"
Enter fullscreen mode Exit fullscreen mode

👉 Same idea, different syntax.


🔹 Step 4: Define Address

let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
Enter fullscreen mode Exit fullscreen mode

What this means:

Your server will run on:

http://127.0.0.1:3000
Enter fullscreen mode Exit fullscreen mode

🐍 FastAPI equivalent:

uvicorn.run(app, host="127.0.0.1", port=3000)
Enter fullscreen mode Exit fullscreen mode

🔹 Step 5: Bind the Server

let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
Enter fullscreen mode Exit fullscreen mode

What this means:

  • Open port 3000
  • Start listening for incoming requests

Think of it like:

“Open the door and wait for visitors”

🐍 Python equivalent:

server.bind(("127.0.0.1", 3000))
server.listen()
Enter fullscreen mode Exit fullscreen mode

🔹 Step 6: Start the Server

axum::serve(listener, app).await.unwrap();
Enter fullscreen mode Exit fullscreen mode

What this means:

  • Take incoming requests from listener
  • Pass them to your app (Router)
  • Run forever

🐍 FastAPI equivalent:

uvicorn.run(app)
Enter fullscreen mode Exit fullscreen mode

🔹 Step 7: Handler Function

async fn root() -> &'static str {
    "Hello, Axum! Hello guys how are you!!!"
}
Enter fullscreen mode Exit fullscreen mode

What this means:

When someone visits /, this function runs and returns a response.

🐍 FastAPI equivalent:

@app.get("/")
async def root():
    return "Hello, Axum!"
Enter fullscreen mode Exit fullscreen mode

🔁 Full Request Flow

Here’s what happens when you open your browser:

Browser → http://127.0.0.1:3000/
        ↓
TcpListener (listening)
        ↓
Axum Server
        ↓
Router matches "/"
        ↓
root() function runs
        ↓
Response sent back
Enter fullscreen mode Exit fullscreen mode

Now Full fastapi code:

from fastapi import FastAPI
import uvicorn

# 1. Create app
app = FastAPI()

# 2. Create route
@app.get("/")
async def root():
    return "Hello, Axum! Hello guys how are you!!!"

# 3. Run server
if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=3000)
Enter fullscreen mode Exit fullscreen mode

🔹 Key Difference (important)

👉 In Axum (Rust):

You manually:
bind address
create listener
start server

👉 In FastAPI (Python):

uvicorn.run() does everything for you

Simple Mental Model

Concept Axum FastAPI
App Router::new() FastAPI()
Route .route("/", get(...)) @app.get("/")
Handler async fn root() async def root()
Server start axum::serve(...) uvicorn.run()
Address SocketAddr host + port

Final Summary

This whole Axum program means:

“Create a web server that listens on port 3000, and when someone visits /, return a simple message.”


If you're already comfortable with FastAPI, you're much closer to mastering Axum than you think. The concepts are the same — Rust just makes things more explicit and safe.

Top comments (0)