Course:Node.js & Express/
Lesson

You ask AI to add authenticationWhat is authentication?Verifying who a user is, typically through credentials like a password or token. to your Express APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses.. It generates an authMiddleware function and adds it to your app. But it places it after the routes that need protection, so every request bypasses authentication entirely. The code looks correct. The structure is wrong.

What middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it. actually is

Middleware is a function that runs during the lifecycle of a request, after Express receives it and before your route handlerWhat is route handler?A Next.js file named route.js inside the app/ directory that handles HTTP requests directly - the App Router equivalent of API routes. sends a response. Think of it as a pipelineWhat is pipeline?A sequence of automated steps (install, lint, test, build, deploy) that code passes through before reaching production.: the request flows through each middleware function in order, and each one can read, modify, or reject the request before passing it along.

// A simple logging middleware
function logger(req, res, next) {
  console.log(`${req.method} ${req.url}`);
  next(); // Pass control to the next middleware or route
}

app.use(logger); // Register it for ALL routes

The key is next(). If a middleware does not call next(), the request stops there. The client waits forever and eventually times out.

ComponentRole
reqThe incoming request object (headers, body, URL, etc.)
resThe response object (used to send data back to the client)
next()Passes control to the next middleware in the chain
next(err)Passes an error to the error-handling middleware
02

The middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it. chain

Middleware runs in the order you register it with app.use(). This order is everything.

const express = require('express');
const app = express();

// 1. Parse JSON bodies (must come before routes that read req.body)
app.use(express.json());

// 2. Log every request
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);
  next();
});

// 3. Check authentication
app.use('/api', (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) return res.status(401).json({ error: 'No token' });
  next();
});

// 4. Routes
app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

If you move express.json() below the routes, req.body is undefined in every POST handler. If you move the auth middleware below the routes, every request passes through without authenticationWhat is authentication?Verifying who a user is, typically through credentials like a password or token.. The code has no errors. The behavior is completely wrong.

AI pitfall
AI generates middleware and routes in a plausible order, but "plausible" is not the same as "correct." The most common AI mistake is putting body parsers after routes, or putting auth middleware at the bottom of the file because it was the last thing you asked for. Always verify middleware order manually.
03

Built-in middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it.

Express ships with three built-in middleware functions that cover the most common needs.

// Parse JSON request bodies (Content-Type: application/json)
app.use(express.json());

// Parse URL-encoded form data (Content-Type: application/x-www-form-urlencoded)
app.use(express.urlencoded({ extended: true }));

// Serve static files from the "public" directory
app.use(express.static('public'));
MiddlewareWhat it doesWhen you need it
express.json()Parses JSON in request body, populates req.bodyAny API that accepts JSON
express.urlencoded()Parses form submissions, populates req.bodyHTML form handling
express.static()Serves files directly from a directoryImages, CSS, client-side JS

Without express.json(), sending a POST request with a JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it. body results in req.body being undefined. This is the number one "it works in Postman but not in my code" debugging scenario.

04

Writing custom middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it.

Custom middleware follows the same pattern: receive req, res, next, do something, call next().

Request timing

function requestTimer(req, res, next) {
  const start = Date.now();

  // Run after the response is sent
  res.on('finish', () => {
    const duration = Date.now() - start;
    console.log(`${req.method} ${req.url} - ${duration}ms`);
  });

  next();
}

app.use(requestTimer);

AuthenticationWhat is authentication?Verifying who a user is, typically through credentials like a password or token. middleware

function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1]; // "Bearer <token>"

  if (!token) {
    return res.status(401).json({ error: 'Authentication required' });
  }

  try {
    const user = verifyToken(token);
    req.user = user; // Attach user to request for downstream handlers
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' });
  }
}

// Apply only to /api routes
app.use('/api', authenticate);

// This route can access req.user because authenticate runs first
app.get('/api/profile', (req, res) => {
  res.json({ user: req.user });
});

Notice the return before res.status(401). Without it, next() would still be called after sending the 401 response, causing the route handlerWhat is route handler?A Next.js file named route.js inside the app/ directory that handles HTTP requests directly - the App Router equivalent of API routes. to execute anyway.

Middleware that modifies the request

A powerful pattern is middleware that attaches data to req so later handlers can use it.

function loadUser(req, res, next) {
  if (req.params.userId) {
    req.user = database.findUser(req.params.userId);
    if (!req.user) {
      return res.status(404).json({ error: 'User not found' });
    }
  }
  next();
}

app.get('/users/:userId', loadUser, (req, res) => {
  // req.user is guaranteed to exist here
  res.json(req.user);
});

You can also pass middleware directly to a route instead of using app.use(). This applies it only to that specific route.

05

Error-handling middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it.

Error-handling middleware has a special signature: four arguments instead of three. Express only calls it when next(err) is called or when an error is thrown.

// Regular middleware - 3 args
app.use((req, res, next) => {
  next();
});

// Error middleware - 4 args (err comes first)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    error: err.message || 'Internal server error'
  });
});

The four-argument signature is not a convention, it is how Express identifies error handlers. If you accidentally omit next from the parameter list, Express treats it as regular middleware and it never receives errors.

AI pitfall
AI frequently generates error middleware with only three parameters (err, req, res), dropping next. Express sees three parameters and treats it as regular middleware, not error middleware. The error handler never fires, and unhandled errors crash your server or return default HTML error pages.
// WRONG: Express sees 3 args, treats as regular middleware
app.use((err, req, res) => {
  res.status(500).json({ error: err.message });
});

// CORRECT: Express sees 4 args, treats as error middleware
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message });
});

Error middleware must be registered after all routes. If you put it before your routes, it will not catch errors from those routes.

Triggering error middleware

app.get('/books/:id', (req, res, next) => {
  try {
    const book = findBook(req.params.id);
    if (!book) {
      const err = new Error('Book not found');
      err.status = 404;
      return next(err); // Passes to error middleware
    }
    res.json(book);
  } catch (err) {
    next(err); // Passes unexpected errors to error middleware
  }
});
06

Common middlewareWhat is middleware?A function that runs between receiving a request and sending a response. It can check authentication, log data, or modify the request before your main code sees it. ordering

A typical Express app registers middleware in this order. Deviating from it causes subtle bugs.

OrderMiddlewareWhy this position
1express.json()Body must be parsed before any handler reads it
2express.urlencoded()Same reason, form data parsing
3CORS middlewareMust set headers before any response is sent
4Logging middlewareLog every request including failed auth
5AuthenticationReject unauthorized requests before hitting routes
6Route handlersBusiness logic
7404 handlerCatch requests that matched no route
8Error handler (4 args)Catch all errors from above