DEV Community

Cover image for Day 25 of #100DaysOfCode — Middleware
M Saad Ahmad
M Saad Ahmad

Posted on

Day 25 of #100DaysOfCode — Middleware

Ever wondered what actually happens between your request leaving the client and the server sending something back? That hidden “in-between” magic is middleware.
Middleware is one of those things in Express that sounds complicated at first… but once it clicks, everything in backend development suddenly makes more sense.

Day 25 was all about understanding what middleware is and how we use it


🍽️ Middleware (Restaurant analogy)

Think of a restaurant:

  • You = the client (making a request)
  • The kitchen = the server (sending a response)
  • The waiter = middleware

The waiter:

  • Takes your order
  • Passes it to the kitchen
  • Brings food back
  • AND can do extra checks (Are you allowed here? Is your order valid?)

That’s exactly what middleware does.

Middleware is simply a function that sits between the request and the response.

It can:

  • ▶ Authenticate users (“Is this user logged in?”)
  • ▶ Log incoming requests
  • ▶ Catch errors
  • ▶ Modify or validate data
  • ▶ Handle permissions
  • ▶ Serve static files
  • ▶ Parse request bodies

🤷‍♂️ Why Do We Need Middleware?

Without middleware, you'd repeat the same logic in every route.
Middleware helps you:

👉 Reuse logic

Write it once → apply everywhere.

👉 Keep code clean

Your route handlers stay focused on actual business logic.

👉 Create pipelines

Middleware stacks like:

Check auth → validate data → run controller → format response
Enter fullscreen mode Exit fullscreen mode

What Does Middleware Look Like?

A middleware function always receives three arguments:

(req, res, next) => {}
Enter fullscreen mode Exit fullscreen mode
  • req → what the client sent
  • res → what you will send back
  • next → passes control to the next middleware

Example:

app.use((req, res, next) => {
  console.log("Someone made a request!");
  next(); // moves to the next middleware
});
Enter fullscreen mode Exit fullscreen mode

Naming doesn’t matter (you can call them a, b, c),
but the order matters:
first = request, second = response, last = next.


🧱 Types of Middleware in Express

Below are all major types of middleware you’ll use.

1. Application-Level Middleware

Runs for every request OR for specific paths.

app.use((req, res, next) => next()); // global

app.use('/admin', checkAuth); // route-specific
Enter fullscreen mode Exit fullscreen mode

2. Route-Level Middleware

Attached directly to specific routes:

app.get('/dashboard', checkAuth, (req, res) => {
  res.send('Dashboard');
});
Enter fullscreen mode Exit fullscreen mode

3. Built-in Middleware (Comes With Express)

express.json()

Parses JSON request bodies.

app.use(express.json());
Enter fullscreen mode Exit fullscreen mode

express.urlencoded()

Parses form data (from HTML forms).

app.use(express.urlencoded({ extended: true }));
Enter fullscreen mode Exit fullscreen mode

express.static()

Serves static assets (HTML, CSS, JS, images).

app.use(express.static('public'));
Enter fullscreen mode Exit fullscreen mode

express.raw()

Parses raw binary data.

app.use(express.raw());
Enter fullscreen mode Exit fullscreen mode

express.text()

Parses plain text requests.

app.use(express.text());
Enter fullscreen mode Exit fullscreen mode

4. Third-Party Middleware

⭐ Morgan → HTTP Logging

npm install morgan
app.use(require('morgan')('dev'));
Enter fullscreen mode Exit fullscreen mode

⭐ CORS → Cross-Origin Requests

npm install cors
app.use(require('cors')());
Enter fullscreen mode Exit fullscreen mode

⭐ Helmet → Security Headers

npm install helmet
app.use(require('helmet')());
Enter fullscreen mode Exit fullscreen mode

⭐ express-rate-limit → Rate Limiting

app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
Enter fullscreen mode Exit fullscreen mode

⭐ cookie-parser → Cookie Parsing

app.use(cookieParser());
console.log(req.cookies);
Enter fullscreen mode Exit fullscreen mode

How Express Processes Middleware (Order Matters!)

Express runs middleware top to bottom in the order they appear in your code.

Incoming Request
       ↓
Middleware 1 → next()
       ↓
Middleware 2 → next()
       ↓
Middleware 3 → res.send()
       ↓
Response Out
Enter fullscreen mode Exit fullscreen mode

Example:

app.use(logger);           // 1st
app.use(express.json());   // 2nd
app.use(checkAuth);        // 3rd

app.get('/dashboard', (req, res) => res.send('hi')); // 4th
Enter fullscreen mode Exit fullscreen mode

If you place checkAuth before express.json(), the body won’t be parsed yet.
This is why middleware order is CRUCIAL.


❌ Error Handling Middleware (Special Type)

Error handlers are detected by Express because they have four arguments:

app.use((err, req, res, next) => {
  res.status(500).send("Something broke!");
});
Enter fullscreen mode Exit fullscreen mode

🤔 When does it run?

Whenever you call:

next(error)
Enter fullscreen mode Exit fullscreen mode

Example:

app.get('/user', (req, res, next) => {
  try {
    throw new Error('User not found');
  } catch (err) {
    next(err);
  }
});
Enter fullscreen mode Exit fullscreen mode

✨ Best Practices

  • Always put error-handling middleware at the end
  • Always include all 4 arguments
  • Use next(err) to trigger it

Example with custom message + status:

app.use((err, req, res, next) => {
  res.status(err.status || 500).json({
    success: false,
    message: err.message || 'Internal Server Error'
  });
});
Enter fullscreen mode Exit fullscreen mode

And a custom error:

app.get('/user/:id', (req, res, next) => {
  const error = new Error('User not found');
  error.status = 404;
  next(error);
});
Enter fullscreen mode Exit fullscreen mode

Full Flow:

Route throws error → next(err) → skip normal middleware → Error handler → Response
Enter fullscreen mode Exit fullscreen mode

🏁 Conclusion

  • Middleware = function between request and response
  • next() = is what moves the chain forward
  • Order matters a lot
  • Built-in middlewares handle parsing + static files
  • Third-party middlewares add security, logging, rate limits, etc.
  • Error handlers use four parameters, always last in the file

Happy coding!

Top comments (0)