Перейти к основному содержимому

Первая программа на Axum

Разработчику Архитектору

Первая программа на Axum

Axum — веб-фреймворк от команды Tokio: типобезопасные маршруты, extractors, middleware через Tower.

Обзор: Фреймворки Rust, Экосистема. База языка: Первая программа на Rust. Тесты: Тестирование в Rust.


Проект

cargo new axum-notes
cd axum-notes

Cargo.toml:

[package]
name = "axum-notes"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

main.rs

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

#[derive(Clone, Serialize)]
struct Note {
id: u32,
text: String,
}

#[derive(Deserialize)]
struct NoteCreate {
text: String,
}

type AppState = Arc<Mutex<(Vec<Note>, u32)>>;

#[tokio::main]
async fn main() {
let state: AppState = Arc::new(Mutex::new((Vec::new(), 1)));

let app = Router::new()
.route("/health", get(health))
.route("/notes", get(list_notes).post(create_note))
.route("/notes/:id", delete(delete_note))
.with_state(state);

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

async fn health() -> &'static str {
"ok"
}

async fn list_notes(State(state): State<AppState>) -> Json<Vec<Note>> {
let guard = state.lock().unwrap();
Json(guard.0.clone())
}

async fn create_note(
State(state): State<AppState>,
Json(body): Json<NoteCreate>,
) -> (StatusCode, Json<Note>) {
let mut guard = state.lock().unwrap();
let id = guard.1;
guard.1 += 1;
let note = Note {
id,
text: body.text,
};
guard.0.push(note.clone());
(StatusCode::CREATED, Json(note))
}

async fn delete_note(
State(state): State<AppState>,
Path(id): Path<u32>,
) -> StatusCode {
let mut guard = state.lock().unwrap();
let len_before = guard.0.len();
guard.0.retain(|n| n.id != id);
if guard.0.len() < len_before {
StatusCode::NO_CONTENT
} else {
StatusCode::NOT_FOUND
}
}
cargo run

Middleware

use tower_http::trace::TraceLayer;

let app = Router::new()
// ... routes
.layer(TraceLayer::new_for_http());

Зависимость: tower-http.


Дальше

  • sqlx + PostgreSQL вместо Vec в памяти;
  • разделение на handlers/, routes/, state/;
  • сравнение с Actix — в 15.md.

См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).