> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 08. Express.js Basics

> Introduction to Express.js, the most popular web framework for Node.js.

# Express.js Basics

In the previous chapters, you learned how to create a basic HTTP server using Node's built-in `http` module. While powerful, it requires significant boilerplate code for real-world applications. This is where **Express.js** comes in.

## The Problem with Raw HTTP

Using the built-in `http` module, even simple tasks become verbose:

```javascript theme={null}
// Without Express - parsing JSON body manually
const http = require('http');

http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/users') {
    let body = '';
    req.on('data', chunk => { body += chunk; });
    req.on('end', () => {
      const user = JSON.parse(body);
      res.writeHead(201, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify(user));
    });
  }
}).listen(3000);
```

This gets even more complex when you add routing, error handling, authentication, and other features.

## Why Express.js?

**Express.js** is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. It's the **de facto standard** for Node.js web development.

### What Express Solves

| Problem                | Express Solution            |
| ---------------------- | --------------------------- |
| Complex routing logic  | Simple, declarative routing |
| Parsing request bodies | Built-in middleware         |
| Managing middleware    | Composable middleware chain |
| Error handling         | Centralized error handlers  |
| Serving static files   | One-line configuration      |

### Express by the Numbers

* **29+ million** weekly downloads on NPM
* Powers **thousands** of production applications
* Extensive ecosystem of middleware packages
* Battle-tested since 2010

## Installation

```bash theme={null}
npm install express
```

## Creating a Basic Server

```javascript theme={null}
const express = require('express');
const app = express();
const PORT = 5000;

app.get('/', (req, res) => {
  res.send('Hello from Express!');
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
```

## Routing

Express makes routing much easier than the raw `http` module.

```javascript theme={null}
// GET request
app.get('/about', (req, res) => {
  res.send('About Page');
});

// POST request
app.post('/contact', (req, res) => {
  res.send('Contact Form Submitted');
});

// Dynamic Parameters
app.get('/users/:id', (req, res) => {
  res.send(`User ID: ${req.params.id}`);
});
```

## Middleware

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 (`next`).

**The Airport Security Analogy:** Think of middleware like the checkpoints you pass through at an airport. Each checkpoint (middleware function) inspects something specific: one checks your ticket (authentication), another scans your bag (body parsing), another checks the no-fly list (authorization). Each checkpoint either lets you through to the next one (`next()`), or stops you and sends you back (`res.status(403).send()`). The order of checkpoints matters--you cannot board (reach the route handler) without passing through all of them first. This is exactly why **the order in which you register middleware with `app.use()` is critical**.

### Creating Custom Middleware

```javascript theme={null}
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl}`);
  next(); // CRITICAL: Call next() to pass control to the next middleware.
           // If you forget next(), the request hangs forever -- the client
           // waits for a response that never comes. This is the #1 Express
           // middleware bug for beginners.
};

// Initialize middleware -- this runs for EVERY request to the server
app.use(logger);
```

### Built-in Middleware

Express has built-in middleware for parsing body data.

```javascript theme={null}
// Parse JSON bodies
app.use(express.json());

// Parse URL-encoded bodies (forms)
app.use(express.urlencoded({ extended: false }));
```

## Serving Static Files

To serve static files such as images, CSS files, and JavaScript files, use the `express.static` built-in middleware function.

```javascript theme={null}
const path = require('path');

// Set 'public' folder as static folder
app.use(express.static(path.join(__dirname, 'public')));
```

## Summary

* **Express.js** simplifies server creation and routing--it is a thin wrapper around Node's `http` module
* Use `app.get()`, `app.post()`, etc., for routing
* **Middleware** executes code between request and response--order of `app.use()` calls matters
* Always call `next()` in middleware unless you are sending a response
* Error-handling middleware must have exactly 4 parameters `(err, req, res, next)` and must be registered last
* `express.json()` parses JSON request bodies
* `express.static()` serves static assets

## Express Router

Organize routes into separate modules:

**routes/users.js**

```javascript theme={null}
const express = require('express');
const router = express.Router();

// All routes here are prefixed with /api/users
router.get('/', (req, res) => {
  res.json([{ id: 1, name: 'John' }]);
});

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

router.post('/', (req, res) => {
  res.status(201).json({ message: 'User created' });
});

module.exports = router;
```

**app.js**

```javascript theme={null}
const express = require('express');
const userRoutes = require('./routes/users');

const app = express();

app.use(express.json());
app.use('/api/users', userRoutes);

app.listen(3000);
```

## Error Handling Middleware

```javascript theme={null}
// Custom error class
class AppError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = true;
  }
}

// Route that throws error
app.get('/error', (req, res, next) => {
  next(new AppError('Something went wrong', 500));
});

// Async error wrapper
const asyncHandler = (fn) => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

// Usage with async routes
app.get('/users', asyncHandler(async (req, res) => {
  const users = await User.find(); // If this throws, error handler catches it
  res.json(users);
}));

// Error handling middleware -- MUST have exactly 4 parameters (err, req, res, next).
// Express identifies error handlers by their arity (parameter count).
// If you accidentally omit one parameter, Express treats it as normal middleware
// and your errors will not be caught. This is a subtle but common bug.
// This middleware MUST be registered AFTER all routes.
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  const statusCode = err.statusCode || 500;
  const message = err.isOperational ? err.message : 'Internal Server Error';
  
  res.status(statusCode).json({
    success: false,
    error: message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
});
```

## Request Object Deep Dive

```javascript theme={null}
app.post('/api/data', (req, res) => {
  // URL parameters (/users/:id)
  console.log(req.params.id);
  
  // Query string (/users?sort=name&order=desc)
  console.log(req.query.sort);    // 'name'
  console.log(req.query.order);   // 'desc'
  
  // Request body (POST/PUT data)
  console.log(req.body);
  
  // Headers
  console.log(req.headers['content-type']);
  console.log(req.get('Authorization'));
  
  // Cookies (requires cookie-parser)
  console.log(req.cookies.session);
  
  // Full URL info
  console.log(req.originalUrl);   // /api/data?sort=name
  console.log(req.path);          // /api/data
  console.log(req.hostname);      // localhost
  console.log(req.ip);            // Client IP
  console.log(req.protocol);      // http or https
  console.log(req.method);        // POST
});
```

## Response Object Methods

```javascript theme={null}
app.get('/response-examples', (req, res) => {
  // Send string
  res.send('Hello World');
  
  // Send JSON
  res.json({ message: 'Hello' });
  
  // Send with status
  res.status(201).json({ created: true });
  
  // Redirect
  res.redirect('/other-route');
  res.redirect(301, '/permanent-redirect');
  
  // Render template (with template engine)
  res.render('index', { title: 'Home' });
  
  // Download file
  res.download('./file.pdf');
  
  // Send file
  res.sendFile('/absolute/path/to/file.html');
  
  // Set headers
  res.set('Content-Type', 'text/html');
  res.set({
    'X-Custom-Header': 'value',
    'Cache-Control': 'no-cache'
  });
  
  // Set cookie
  res.cookie('session', 'abc123', {
    httpOnly: true,
    secure: true,
    maxAge: 3600000
  });
  
  // Clear cookie
  res.clearCookie('session');
});
```

## Third-Party Middleware

```javascript theme={null}
const express = require('express');
const helmet = require('helmet');       // Security headers
const cors = require('cors');           // Cross-origin requests
const morgan = require('morgan');       // Logging
const compression = require('compression'); // Gzip
const rateLimit = require('express-rate-limit'); // Rate limiting

const app = express();

// IMPORTANT: Middleware order matters! A common production setup applies
// security middleware first, then logging, then body parsing, then routes.
// If you put body parsing AFTER your routes, req.body will be undefined.

// Security headers
app.use(helmet());

// CORS
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST'],
  credentials: true
}));

// Logging
app.use(morgan('dev'));  // or 'combined' for production

// Compression
app.use(compression());

// Rate limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api', limiter);

// Body parsers
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
```

## Application Structure Best Practice

```
project/
├── src/
│   ├── config/
│   │   └── db.js
│   ├── controllers/
│   │   └── userController.js
│   ├── middleware/
│   │   ├── auth.js
│   │   └── errorHandler.js
│   ├── models/
│   │   └── User.js
│   ├── routes/
│   │   ├── index.js
│   │   └── userRoutes.js
│   ├── services/
│   │   └── userService.js
│   ├── utils/
│   │   └── helpers.js
│   └── app.js
├── tests/
├── .env
├── .gitignore
├── package.json
└── server.js
```
