In module 2, we will dive into two fundamental aspects of Express.js: 
            
            
             Routing and Middleware. These are essential concepts that empower 
            
            
             developers to create dynamic and efficient web applications.
            
            
             2.1 Creating Routes - Handling HTTP Requests 
            
            
             Routing in Express.js
            
            
             Routing is a core concept in Express.js that allows you to define how 
            
            
             your application responds to different HTTP requests and URL paths. 
            
            
             In Express, routes are defined using HTTP methods (such as GET, 
            
            
             POST, PUT, DELETE) and URL patterns. Each route specifies a function 
            
            
             to execute when a request matching that route is received.
            
            
             Creating Basic Routes
            
            
             Here's how to create basic routes in Express:
            
            
             - javascript
            
            
             const express = require('express');
            
            
             const app = express();
            
            
             // Define a route for GET requests to the root path
            
            
             app.get('/', (req, res) => {
            
            
              res.send('This is the homepage');
            
            
             });
            
            
             // Define a route for POST requests to the “/submit” path
            
            
             app.post('/submit', (req, res) => {
            
            
              res.send('Form submitted successfully');
            
            
             });
            
            
             // Define a route for all other paths
            
            
             app.use((req, res) => {
            
            
              res.status(404).send('Page not found');
            
            
             });
            
            
             // Start the server
            
            
             const port = 3000;
            
            
             app.listen(port, () => {
            
            
              console.log(`Server is running on port ${port}`);
            
            
             });
            
            
             In this example:
            
            
              We define a route for HTTP GET requests to the root path ('/'). 
            
            
             When a user accesses the root URL, they receive the response 
            
            
             'This is the homepage.'
            
            
              We define a route for HTTP POST requests to the '/submit' 
            
            
             path. This is often used for form submissions.
            
            
              We use a catch-all route (expressed as “
             app.use()”) to handle 
            
            
             all other paths. If a user requests an undefined path, they 
            
            
             receive a 'Page not found' response.
            
            
              The server is started on port 3000.
            
            
             Dynamic Routes
            
            
             Express also allows you to create dynamic routes using parameters in 
            
            
             the URL. Parameters are indicated by a colon followed by the 
            
            
             parameter name in the URL pattern. Here's an example:
            
            
             - javascript
            
            
             app.get('/users/:id', (req, res) => {
            
            
              const userId = req.params.id;
            
            
              res.send(`User ID: ${userId}`);
            
            
             });
            
            
             In this example, the “:id” parameter is a placeholder for any value in 
            
            
             the URL. When a user accesses a URL like '/users/123', the value 
            
            
             '123' is extracted from the URL and made available in 
            
            
             “req.params.id”. You can then use this value to perform actions or 
            
            
             look up data related to that user.
            
            
             2.2 Defining Middleware Functions ….
            
            
             Middleware functions are a powerful aspect of Express.js that allow 
            
            
             you to add processing logic to incoming requests before they reach 
            
            
             your route handlers. Middleware functions can perform tasks such as 
            
            
             request parsing, authentication, logging, and error handling. They are 
            
            
             executed in the order in which they are defined in your Express 
            
            
             application.
            
            
             Creating Middleware Functions
            
            
             Here's how you can create and use middleware functions in Express:
            
            
             - javascript
            
            
             // Example middleware function
            
            
             function logRequest(req, res, next) {
            
            
              console.log(`Received ${req.method} request for ${req.url}`);
            
            
              next(); // Call next() to pass control to the next middleware or route 
            
            
             handler
            
            
             }
            
            
             // Using the middleware function
            
            
             app.use(logRequest);
            
            
             // Define a route that uses the middleware
            
            
             app.get('/protected', (req, res) => {
            
            
              res.send('This route is protected');
            
            
             });
            
            
             In this example:
            
            
              We define a middleware function “logRequest” that logs 
            
            
             information about incoming requests, such as the HTTP method 
            
            
             and URL.
            
            
              The “next()” function is called to pass control to the next 
            
            
             middleware or route handler. This is crucial to ensure that the 
            
            
             request continues to be processed after the middleware logic is 
            
            
             executed.
            
            
              We use “app.use()” to apply the “logRequest” middleware to all 
            
            
             routes, meaning it will be executed for every incoming request.
            
            
             
            
            Using Middleware for Authentication
            
             Middleware functions are often used for implementing 
            
            
             authentication in Express applications. Here's a simplified example:
            
            
             - javascript
            
            
             // Example middleware for authentication
            
            
             function authenticate(req, res, next) {
            
            
              const isAuthenticated = /* Check if user is authenticated */;
            
            
              if (isAuthenticated) {
            
            
              next(); // Continue processing if authenticated
            
            
              } else {
            
            
              res.status(401).send('Unauthorized');
            
            
              }
            
            
             }
            
            
             // Apply authentication middleware to a specific route
            
            
             app.get('/protected', authenticate, (req, res) => {
            
            
              res.send('This route is protected');
            
            
             });
            
            
             In this example:
            
            
              The “authenticate” middleware checks if the user is 
            
            
             authenticated. If authenticated, it calls “next()” to allow the 
            
            
             request to proceed; otherwise, it sends a 'Unauthorized' 
            
            
             response with a status code of 401.
            
            
              We apply the “authenticate” middleware only to the 
            
            
             '/protected' route, ensuring that it's executed only for that 
            
            
             specific route.
            
            
             2.3 Routing Parameters and Route Chaining
            
            
             Routing Parameters
            
            
             Express.js allows you to extract data from URL parameters, as shown 
            
            
             earlier with dynamic routes. You can access these parameters using 
            
            
             “
             req.params”. Here's a more detailed example:
            
            
             - javascript
            
            
             app.get('/users/:id/posts/:postId', (req, res) => {
            
            
              const userId = req.params.id;
            
            
              const postId = req.params.postId;
            
            
              res.send(`User ID: ${userId}, Post ID: ${postId}`);
            
            
             });
            
            
             In this example, we define a route that captures two parameters, 
            
            
             “:id” and “:postId”, from the URL. These values are then accessed 
            
            
             using “req.params”.
            
            
             Route Chaining
            
            
             Route chaining is a technique used to apply multiple route handlers 
            
            
             to a single route. This is particularly useful for breaking down the 
            
            
             handling of a route into smaller, reusable components.
            
            
             - javascript
            
            
             // Middleware for authentication
            
            
             function authenticate(req, res, next) {
            
            
              const isAuthenticated = /* Check if user is authenticated */;
            
            
              if (isAuthenticated) {
            
            
              next();
            
            
              } else {
            
            
              res.status(401).send('Unauthorized');
            
            
              }
            
            
             }
            
            
             // Middleware for logging
            
            
             function logRequest(req, res, next) {
            
            
              console.log(`Received ${req.method} request for ${req.url}`);
            
            
              next();
            
            
             }
            
            
             // Define a route and chain the middleware
            
            
             app.get(
            
            
              '/protected',
            
            
              authenticate,
            
            
              logRequest,
            
            
              (req, res) => {
            
            
              res.send('This route is protected');
            
            
              }
            
            
             );
            
            
             In this example:
            
            
              We define two middleware functions, “authenticate” and 
            
            
             “logRequest”.
            
            
              We use route chaining by passing an array of middleware 
            
            
             functions followed by the route handler function to “app.get()”. 
            
            
             This ensures that both “authenticate” and “logRequest” 
            
            
             middleware functions are executed before the final route 
            
            
             handler.
            
            
             Route chaining allows you to create modular and organized routes by 
            
            
             breaking them down into smaller, reusable middleware components