Module 10 • Lesson 52

Web Servers with Axum

📚 11 min💻 Free🦀 nixus.pro

Web Servers with Axum

// Cargo.toml:
// axum = "0.7"
// tokio = { version = "1", features = ["full"] }
// serde = { version = "1", features = ["derive"] }
// serde_json = "1"

use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::Json,
    routing::{get, post, delete},
    Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    id: u64,
    name: String,
    email: String,
}

type SharedState = Arc>>;

async fn list_users(State(state): State) -> Json> {
    let users = state.lock().unwrap();
    Json(users.values().cloned().collect())
}

async fn get_user(
    Path(id): Path,
    State(state): State,
) -> Result, StatusCode> {
    let users = state.lock().unwrap();
    users.get(&id).cloned().map(Json).ok_or(StatusCode::NOT_FOUND)
}

async fn create_user(
    State(state): State,
    Json(user): Json,
) -> (StatusCode, Json) {
    let mut users = state.lock().unwrap();
    users.insert(user.id, user.clone());
    (StatusCode::CREATED, Json(user))
}

#[tokio::main]
async fn main() {
    let state: SharedState = Arc::new(Mutex::new(HashMap::new()));

    let app = Router::new()
        .route("/users", get(list_users).post(create_user))
        .route("/users/:id", get(get_user))
        .with_state(state);

    println!("Server on http://localhost:3000");
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

🎯 Practice

  1. Add a DELETE /users/:id endpoint
  2. Add a PATCH /users/:id endpoint for partial updates
  3. Add query parameters to list_users: ?limit=10&offset=0
  4. Add middleware that logs every request with method, path, and status code

🎉 Key Takeaways