Skip to main content

Express.js Deep Dive - Complete Technical Guide

Express.js is a fast, unopinionated, minimalistic web framework for Node.js, designed for building web applications and APIs.

1. Express.js Fundamentals

Why Express.js Over Node.js?

AspectNode.jsExpress.js
Code LengthLengthy, verboseConcise, minimal
Built-in FunctionsLimitedMany helper functions
RoutingManual implementationSimple routing methods
MiddlewareComplex to implementBuilt-in middleware support
Development SpeedSlowerFaster

Key Characteristics

  1. Fast: Optimized request handling and efficient routing.
  2. Unopinionated: Developer has freedom to structure code (no enforced MVC).
  3. Minimalistic: Built-in methods like res.json() and res.send() reduce boilerplate.

2. Project Structure & Setup

package.json configuration

The package.json file manages your project’s dependencies and metadata.
TypePurposeProduction
dependenciesRequired to run the app (e.g., express, mongoose)✅ Installed
devDependenciesOnly for development (e.g., nodemon, jest)❌ Not installed
Scripts for speed:
"scripts": {
  "start": "node index.js",
  "dev": "nodemon index.js"
}

3. HTTP Methods & CRUD Operations

MethodCRUDPurposeIdempotent?
GETReadFetch/retrieve data✅ Yes
POSTCreateCreate new resource❌ No
PUTUpdateReplace entire resource✅ Yes
PATCHUpdateUpdate partial resource✅ Yes
DELETEDeleteRemove resource✅ Yes

PUT vs PATCH

  • PUT: Replaces the entire document. If fields are missing in the request, they may be removed if not handled.
  • PATCH: Updates only the specified fields, preserving the rest of the document.

4. Request-Response Cycle

The Request Object (req)

Contains all incoming client data:
  • req.body: Data from POST/PUT/PATCH.
  • req.params: Dynamic segments in URL (e.g., /users/:id).
  • req.query: Optional filters after ? (e.g., ?sort=asc).
  • req.headers: Authentication tokens, content-types.

The Response Object (res)

Used to send data back:
  • res.status(code): Set HTTP status.
  • res.json(data): Send JSON response.
  • res.send(data): Send plain text/HTML.
  • res.redirect(url): Redirect client.

5. URL Structure & Routing

https://example.com:3000/api/users/123?sort=asc#section
└─┬─┘ └────┬─────┘└─┬─┘└───┬───┘└─┬─┘└─────┬─────┘└──┬──┘
Protocol   Domain  Port   Path   Params  Query     Fragment
  • Route Parameters (req.params): Used for required identifiers.
  • Query Strings (req.query): Used for optional filters (sorting, pagination).

6. Middleware Architecture

Middleware are functions that execute between the request and the response. They follow a chain pattern.
app.use((req, res, next) => {
  console.log('Logging request...');
  next(); // Passes control to next middleware
});

Types of Middleware

  1. Application-level: app.use()
  2. Router-level: router.use()
  3. Built-in: express.json(), express.static()
  4. Third-party: cors(), morgan(), helmet()
  5. Error-handling: Middleware with 4 arguments (err, req, res, next)

7. Interview Questions & Answers

Answer: Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. They can:
  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware in the stack.
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
Answer:
  • req.params: Extracted from the URL path defined by placeholders like /:userId. They are used for identifying a specific resource (e.g., /users/123).
  • req.query: Extracted from the query string after the ?. They are used for filtering or modifying the result of a request (e.g., /users?sort=desc).
Answer: Errors are handled using special Error-handling middleware. Unlike regular middleware, these have four arguments: (err, req, res, next).
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
In asynchronous code, you must pass errors to next(err) to trigger this middleware.
Answer: It is a built-in middleware function in Express that parses incoming requests with JSON payloads. It is based on the body-parser library. Without it, your application won’t be able to read data sent in the request body via req.body (it will be undefined).
app.use((req, res, next) => {
  console.log('A');
  next();
});

app.get('/', (req, res) => {
  console.log('B');
  res.send('Done');
});
Answer: When a GET request is made to /, the output will be A followed by B. The request first hits the application-level middleware (A), calls next(), then proceeds to the route handler (B).