Copied to Clipboard
🚀 What Happens When You Run This?
- You visit
http://localhost:3000
- Middleware runs before
- Handler runs (waits 2 seconds)
- Middleware runs after
- Response is sent
Console output:
->Before handler
<- After handler
Time: 2.00s
🔥 Now Let’s Explain the Confusing Parts
This is the most important section.
1️⃣ req: Request<axum::body::Body>
req: Request<axum::body::Body>
What is this?
This is the incoming HTTP request.
It contains:
- URL (
/)
- headers
- body (data sent by client)
Why is it written like this?
Rust is very strict about types, so it says:
-
Request<T> → request with some body type
-
axum::body::Body → the actual body format
👉 Simple meaning:
"This is the full request coming from the client"
You can just think:
req = user request
2️⃣ next: middleware::Next
next: middleware::Next
What is this?
This represents the next step in the chain.
That could be:
- your handler
- or another middleware
Simple meaning:
"What should happen after this middleware?"
3️⃣ The MOST IMPORTANT Line
let res = next.run(req).await;
What is happening here?
This line says:
"Send the request forward and wait for the response"
Break it down:
| Part |
Meaning |
next.run(...) |
call the next step |
req |
pass the request |
.await |
wait for result |
res |
store the response |
Why is this REQUIRED?
Without this line:
- the handler will never run
- the request will stop inside middleware
👉 Middleware must always decide:
- forward request ❓
- or block it ❌
4️⃣ tracing_subscriber::fmt::init();
tracing_subscriber::fmt::init();
What is this?
This sets up logging system.
Why do we need it?
Because this line alone does nothing:
info!("Server running...");
Rust logging works like this:
-
tracing → creates logs
-
tracing-subscriber → displays logs
Without init():
- logs are silently ignored ❌
With init():
- logs are printed to console ✅
5️⃣ info!
info!("Server running on http://0.0.0.0:3000");
What is this?
This is a log message, like println! but better.
Why use it instead of println!?
Because it supports:
- log levels (
info, debug, error)
- filtering
- structured logging
👉 Example:
RUST_LOG=debug cargo run
⚡ Quick Comparison
| Feature |
println! |
info! |
| Works instantly |
✅ |
❌ (needs init) |
| Log levels |
❌ |
✅ |
| Production use |
❌ |
✅ |
🎯 Final Mental Model
Whenever you see middleware, think:
1. Receive request
2. Do something BEFORE
3. Call next.run(req)
4. Do something AFTER
5. Return response
🏁 Summary
-
req → the incoming request
-
next → what happens next
-
next.run(req).await → pass control forward
-
tracing_subscriber::fmt::init() → enable logging
-
info! → structured logging
Middleware is not complex — it just looks complex.
Once you understand the flow, everything becomes simple.
If you want to go further, next steps could be:
- Authentication middleware
- Logging every request
- Error handling middleware
Just continue building — that’s the best way to learn 🚀