06 — Middleware
Hub › JavaScript › Advanced › 06 Middleware
Goal: add logging, error handling, and auth enforcement as Express middleware.
Logging middleware
Create middleware/logger.js:
js
function logger(req, _res, next) {
const start = Date.now();
const originalEnd = res.end;
res.end = function (...args) {
const ms = Date.now() - start;
console.log(`${req.method} ${req.originalUrl} ${res.statusCode} ${ms}ms`);
return originalEnd.apply(this, args);
};
next();
}
module.exports = logger;Auth middleware
Create middleware/auth.js:
js
const jwt = require("jsonwebtoken");
const JWT_SECRET = process.env.JWT_SECRET || "dev-secret-change-me";
function authenticate(req, res, next) {
const header = req.headers.authorization;
if (!header || !header.startsWith("Bearer ")) {
return res.status(401).json({ error: "missing authorization header" });
}
try {
const payload = jwt.verify(header.split(" ")[1], JWT_SECRET);
req.user = payload;
next();
} catch {
return res.status(401).json({ error: "invalid or expired token" });
}
}
module.exports = authenticate;Error handler
Create middleware/errorHandler.js:
js
function errorHandler(err, _req, res, _next) {
console.error("Unhandled error:", err);
res.status(500).json({ error: "internal server error" });
}
module.exports = errorHandler;Wire all middleware into app.js
js
const logger = require("./middleware/logger");
const authenticate = require("./middleware/auth");
const errorHandler = require("./middleware/errorHandler");
const authRouter = require("./auth");
app.use(logger);
app.use(express.json());
app.use(authRouter);
// Protected routes
app.get("/api/todos", authenticate, async (req, res, next) => {
try {
const todos = await db.getAllTodos(req.user.userId);
res.json(todos);
} catch (err) {
next(err);
}
});
app.post("/api/todos", authenticate, async (req, res, next) => {
try {
const { text } = req.body;
if (!text) return res.status(400).json({ error: "text is required" });
const todo = await db.createTodo(text, req.user.userId);
res.status(201).json(todo);
} catch (err) {
next(err);
}
});
// PATCH and DELETE follow the same pattern — add authenticate, pass req.user.userId
app.use(errorHandler);Remove the old unprotected route handlers for
/api/todos— they are replaced by these authenticated versions.
Checkpoint
bash
node server.js &
sleep 1
# Without token
curl -s http://localhost:3000/api/todos
# {"error":"missing authorization header"}
# Login
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"alice@test.com","password":"secret123"}' | node -e "process.stdin.on('data',d=>console.log(JSON.parse(d).token))")
# Create with token
curl -s -X POST http://localhost:3000/api/todos \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"text":"authenticated todo"}'
# {"id":1,"text":"authenticated todo","done":false,"user_id":1,"created_at":"..."}
kill %1 2>/dev/nullThe server log should show something like:
POST /api/auth/login 200 42ms
POST /api/todos 201 8msNext: 07 Docker deploy