Middleware และ Tower
Express app.use vs Tower layers
หัวข้อที่มีชื่อว่า “Express app.use vs Tower layers”ใน Express middleware คือ function (req, res, next) => void ที่คุณลงทะเบียนด้วย app.use() ใน Axum middleware คือ Tower layer — เป็น wrapper แบบ composable รอบ Service แนวคิดเหมือนกัน (intercept → process → forward) แต่ Tower เป็น protocol-agnostic และทำงานที่ compile time
// Express — register middleware globallyimport express from 'express';import cors from 'cors';import morgan from 'morgan';
const app = express();app.use(cors({ origin: 'https://myapp.com' }));app.use(morgan('combined'));app.use(express.json());
app.get('/users', listUsers);use axum::{routing::get, Router};use tower_http::{cors::CorsLayer, trace::TraceLayer};use tower::ServiceBuilder;use http::HeaderValue;
let app = Router::new() .route("/users", get(list_users)) .layer( ServiceBuilder::new() .layer(TraceLayer::new_for_http()) .layer( CorsLayer::new() .allow_origin("https://myapp.com".parse::<HeaderValue>().unwrap()) .allow_methods([http::Method::GET, http::Method::POST]) ) );CORS layer
หัวข้อที่มีชื่อว่า “CORS layer”tower-http มี CorsLayer ที่ใช้งานได้เหมือน cors npm package เพิ่มใน Cargo.toml ด้วย tower-http = { version = "0.5", features = ["cors"] }
use tower_http::cors::{Any, CorsLayer};use axum::http::Method;
let cors = CorsLayer::new() .allow_origin(Any) // any origin (dev only) .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE]) .allow_headers(Any);
let app = Router::new() .route("/users", get(list_users)) .layer(cors);Request tracing / logging
หัวข้อที่มีชื่อว่า “Request tracing / logging”TraceLayer ของ tower-http รวมกับ tracing เพื่อ log ทุก request/response เพิ่ม tower-http = { version = "0.5", features = ["trace"] } ใน Cargo.toml
use tower_http::trace::TraceLayer;
let app = Router::new() .route("/users", get(list_users)) .layer(TraceLayer::new_for_http());เริ่ม app ด้วย RUST_LOG=tower_http=debug cargo run เพื่อดู structured request logs
Route-scoped vs global layers
หัวข้อที่มีชื่อว่า “Route-scoped vs global layers”Tower layer จะ wrap service ที่อยู่ชั้นล่างถัดไป คุณแนบ layer กับทั้ง router หรือเจาะจงเฉพาะ route group ก็ได้:
// Express — scoped middlewareimport authMiddleware from './auth';
const protectedRouter = express.Router();protectedRouter.use(authMiddleware);protectedRouter.get('/profile', getProfile);
app.use('/api', protectedRouter);use axum::Router;use tower_http::auth::RequireAuthorizationLayer;
// Layer applied only to the protected sub-routerlet protected_routes = Router::new() .route("/profile", get(get_profile)) .layer(RequireAuthorizationLayer::bearer("secret-token"));
let app = Router::new() .route("/health", get(health)) .nest("/api", protected_routes);รันบนเครื่องของคุณ — middleware ต้องการ Axum server ที่กำลังทำงาน รันด้วย
RUST_LOG=tower_http=debug cargo run