Body Parsing: What express.json() Actually Solves
Without any body parser, req.body is undefined. The request body arrives as a raw stream of bytes in chunks. express.json() is middleware that listens to the incoming body stream, waits for all chunks to arrive, joins them into one Buffer, parses that Buffer as JSON text, and attaches the result to req.body.
app.use(express.json());
app.post('/login', (req, res) => {
console.log(req.body); // { email: '...', password: '...' }
});
Cookies: The Header Nobody Explains Properly
Every request from a browser that has cookies set automatically carries a Cookie header — plain text, semicolon-separated. Without cookie-parser, that's just one long unparsed string sitting in req.headers.cookie. With it:
app.use(cookieParser());
app.get('/dashboard', (req, res) => {
console.log(req.cookies); // { sessionId: 'abc123', theme: 'dark' }
});
Router: The Missing Middle Layer
express.Router() is a mini, self-contained Express app you can build separately and plug in. The prefix is stripped off before the router even looks at the path, making routers composable.
// routes/userRoutes.js
const router = require('express').Router();
router.get('/', getAllUsers);
router.post('/', createUser);
router.get('/:id', getUserById);
module.exports = router;
// app.js
const userRoutes = require('./routes/userRoutes');
app.use('/users', userRoutes);
Error Handling: Where Bugs Actually Go to Die
Synchronous errors: try/catch works directly. Async errors (Promise): try/catch works ONLY if you await it. Error inside a callback: try/catch around the callback CANNOT catch it because the callback runs later, outside the try block.
// This does NOT catch the error:
try {
fs.readFile('missing.txt', (err, data) => {
if (err) throw err; // throws later, outside try
});
} catch (e) {
console.log('caught it'); // never runs
}
With Promises + async/await, await genuinely pauses your function until the result (or error) comes back — so try/catch around it works correctly.
async function loadUser(id) {
try {
const user = await db.query('SELECT * FROM users WHERE id = ?', [id]);
return user;
} catch (err) {
console.error('DB query failed:', err.message);
throw err;
}
}
Express has a built-in concept of error middleware — a special function with four parameters: (err, req, res, next). When a route handler throws or calls next(err), Express skips all normal middleware and jumps straight to the error-handling middleware.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong' });
});
Error middleware must sit at the very end of the chain, after all routes.
For errors Express doesn't know about, use process-level events:
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Promise rejection:', reason);
// log it, alert someone, then usually shut down gracefully
});
process.on('uncaughtException', (err) => {
console.error('Uncaught exception:', err);
process.exit(1); // the process is now in an unknown state — restart it
});
An uncaught exception means the process's internal state could be anything. Continuing from a corrupted state is dangerous. Production Node apps run under a process manager (PM2, Docker with restart policy, Kubernetes) that automatically restarts the process on exit.
Two Directions Node Never Confuses
Everything Node does falls into exactly two directions:
Direction 1 — Incoming Events: The outside world tells Node something happened. Path: OS → libuv → Event Loop → JavaScript. Examples: HTTP request arrives, TCP connection opens, WebSocket message arrives.
Direction 2 — Outgoing Async Operations: JavaScript asks Node to go do something. Path: JavaScript → libuv → Worker Thread → OS → Disk/DB, then result comes back through libuv → Event Loop → callback. Examples: fs.readFile(), crypto.pbkdf2(), dns.lookup().
An incoming HTTP request and a fs.readFile() call both pass through libuv and the event loop, but they enter from opposite directions. An HTTP request never touches the thread pool; a file read almost always does.
The Honest "What Actually Fails" Section
The source article mentions this section but it was truncated. Based on the material, common failures include: not handling async errors, forgetting to use express.json(), and not having error middleware at the end.
Next Steps
Go through your existing Express projects and check:
- Is
express.json()applied before all routes? - Is
cookie-parserapplied if you use cookies? - Are routes organized using
Router()? - Is there an error-handling middleware at the end?
- Are async route handlers wrapped with try/catch?
- Are
unhandledRejectionanduncaughtExceptionhandlers registered?
If any of these are missing, fix them now before they break at 2 AM.

