Course:Node.js & Express/
Lesson

You ask an AI to build an APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. for a bookstore. In seconds it gives you a file with app.get, app.post, app.put, and app.delete calls. The routes look reasonable. But when you test them, /books/featured returns a 404 because a wildcard route /books/:id above it swallowed the request first. This is the kind of mistake you need to catch.

How routing works in Express

Express matches incoming requests against routes in the order they are defined. The first route that matches the HTTPWhat is http?The protocol browsers and servers use to exchange web pages, API data, and other resources, defining how requests and responses are formatted. method and URL pattern wins. If no route matches, Express returns a 404.

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

// Route: GET /books
app.get('/books', (req, res) => {
  res.json({ books: [] });
});

// Route: POST /books
app.post('/books', (req, res) => {
  res.json({ message: 'Book created' });
});

app.listen(3000);

Each route has three parts: the HTTP method (get, post, put, delete), the path pattern (/books), and a handler function.

HTTP methodPurposeExample
GETRead dataFetch a list of books
POSTCreate dataAdd a new book
PUTReplace dataUpdate an entire book record
PATCHPartial updateChange just the book title
DELETERemove dataDelete a book
02

Route parameters

Route parameters are named segments in the URL path that Express extracts for you. They start with a colon.

// :id is a route parameter
app.get('/books/:id', (req, res) => {
  const bookId = req.params.id; // "42" if URL is /books/42
  res.json({ bookId });
});

// Multiple parameters
app.get('/users/:userId/orders/:orderId', (req, res) => {
  const { userId, orderId } = req.params;
  res.json({ userId, orderId });
});

Parameters are always strings. If your route is /books/:id and someone requests /books/42, then req.params.id is the string "42", not the number 42. You need to convert it yourself.

AI pitfall
AI almost never converts route parameters to the correct type. It will write const book = books.find(b => b.id === req.params.id) where b.id is a number and req.params.id is a string. The comparison always fails silently because 42 === "42" is false in JavaScript.
03

Query strings

Query strings pass optional data in the URL after a ?. They are used for filtering, sorting, and paginationWhat is pagination?Splitting a large set of results into smaller pages so the server and client only handle a manageable chunk at a time., not for identifying a specific resource.

// URL: /books?genre=fiction&sort=title&page=2
app.get('/books', (req, res) => {
  const { genre, sort, page } = req.query;
  // genre = "fiction", sort = "title", page = "2"
  res.json({ genre, sort, page });
});
SourceAccessExample URLUse case
Route paramsreq.params.id/books/42Identify a specific resource
Query stringreq.query.genre/books?genre=fictionFilter, sort, paginate
Request bodyreq.body.titlePOST /booksSend data to create or update
04

The handler function

Every 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. receives three arguments. The third one, next, is optional but critical for error handling and 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. chains.

app.get('/books/:id', (req, res, next) => {
  const book = findBook(req.params.id);

  if (!book) {
    // Option 1: Send a response directly
    return res.status(404).json({ error: 'Book not found' });
  }

  // Option 2: Pass an error to Express error handler
  // next(new Error('Something went wrong'));

  res.json(book);
});

The return before res.status(404) is important. Without it, Express continues executing the restWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. of the handler and tries to send a second response, which crashes.

AI pitfall
AI frequently forgets the return before early responses. You will see code like res.status(404).json({ error: 'Not found' }); res.json(book); where both lines execute. In production, this causes "Cannot set headers after they are sent to the client" errors.
05

Route order matters

Express checks routes top to bottom. A parameterized route like /books/:id matches any path segment, including words like featured or new.

// BUG: /books/featured is caught by :id route
app.get('/books/:id', (req, res) => {
  // req.params.id = "featured" - then database lookup fails
  res.json({ book: findById(req.params.id) });
});

app.get('/books/featured', (req, res) => {
  // This route NEVER runs because :id above matches first
  res.json({ featured: getFeaturedBooks() });
});

The fix is to put specific routes before parameterized routes:

// FIXED: specific route first
app.get('/books/featured', (req, res) => {
  res.json({ featured: getFeaturedBooks() });
});

app.get('/books/:id', (req, res) => {
  res.json({ book: findById(req.params.id) });
});

This is one of the most common bugs in AI-generated Express code. AI does not think about route order, it generates routes in whatever sequence feels logical for the prompt, not for Express matching algorithm.

06

Router modules

As your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. grows, putting every route in a single file becomes unmanageable. Express Router lets you group related routes into separate files.

// routes/books.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ books: [] });
});

router.get('/:id', (req, res) => {
  res.json({ book: {} });
});

router.post('/', (req, res) => {
  res.json({ message: 'Created' });
});

module.exports = router;
// app.js
const express = require('express');
const app = express();
const booksRouter = require('./routes/books');

// All routes in booksRouter are now prefixed with /books
app.use('/books', booksRouter);

app.listen(3000);

Inside the router file, paths are relative to the mount point. So router.get('/') handles GET /books and router.get('/:id') handles GET /books/42.

When AI generates routers

AI generally structures routers correctly, but watch for two mistakes: (1) forgetting to export the router with module.exports = router, and (2) using absolute paths like /books/:id inside the router instead of relative paths like /:id, which causes the route to be /books/books/:id when mounted.

PatternRoute in router fileMounted atFinal URL
Correctrouter.get('/:id')/books/books/:id
Wrongrouter.get('/books/:id')/books/books/books/:id