UNIT III: Node.js & Express.
js – Well-Structured
Notes
1. Introduction to Node.js
Node.js is an open-source, cross-platform JavaScript runtime environment that allows
developers to execute JavaScript code outside the browser, mainly on the server side. Created
by Ryan Dahl in 2009 and powered by the Google Chrome V8 engine, Node.js is designed for
building scalable network applications, such as web servers and APIs, using an event-driven,
non-blocking I/O model.
Key Features:
Enables JavaScript for both client-side and server-side programming.
Promotes code reuse and a unified development stack.
Ideal for real-time applications (e.g., chat apps, collaborative tools, streaming services).
2. Advantages of Node.js
1. Asynchronous and Event-Driven
Handles multiple requests simultaneously with non-blocking I/O. Highly efficient for data-
intensive, real-time applications.
2. Single Programming Language
JavaScript is used on both client and server sides, reducing learning curve and enabling
code sharing.
3. High Performance
Built on the V8 engine, compiles JavaScript to native machine code for fast execution. The
event loop ensures efficient concurrent request handling.
4. Scalability
Supports both vertical and horizontal scaling. Can handle thousands of simultaneous
connections with minimal overhead.
5. Rich Ecosystem
npm provides a vast repository of open-source libraries and modules, accelerating
development.
6. Cross-Platform
Runs on Windows, Linux, and macOS, making deployment flexible.
7. Active Community Support
Large, active community ensures continuous improvement and abundant resources.
3. Node.js Process Model
Node.js uses a single-threaded event loop model for handling concurrent client requests
efficiently, unlike traditional multi-threaded servers.
Key Components:
Event Loop:
Continuously checks for new events or requests in the event queue and processes them one
by one, allowing many connections without creating new threads.
Non-blocking I/O:
Delegates blocking operations (like file I/O or database queries) to the system kernel or a
thread pool. Callbacks are added to the event queue once operations complete.
Thread Pool:
For CPU-intensive or blocking tasks, Node.js uses a thread pool (via libuv) to execute tasks
in the background, freeing the main thread.
Diagram (Text Description):
Client Requests
|
v
Event Queue
|
v
Event Loop <----------------------|
| |
v |
Non-blocking Tasks Blocking Tasks (Thread Pool)
| |
v v
Response Callback/Event
| |
+----------------------------+
Example:
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
Here, fs.readFile is non-blocking. Node.js can handle other requests while waiting for the file to
be read.
4. Node.js Modules
Node.js uses a modular architecture, enabling code organization into reusable modules.
Types of Modules:
1. Core Modules:
Built-in (e.g., fs, http, path, os).
2. Third-Party Modules:
Installed via npm (e.g., express, mongoose, lodash).
3. Custom Modules:
Created by developers for specific applications.
How to Use Modules:
Importing a Module:
const http = require('http');
Exporting from a Custom Module:
// greet.js
module.exports = function(name) {
return `Hello, ${name}`;
};
// app.js
const greet = require('./greet');
console.log(greet('World'));
Advantages:
Code reusability and maintainability
Separation of concerns
Easier testing and debugging
5. Express.js: Introduction, First App, Routing, and MVC
Introduction to Express Framework
Express.js is a minimal, flexible Node.js web application framework. It simplifies building server-
side applications and APIs by providing tools for routing, middleware, and template rendering.
Getting Started with Express & Your First Express App
Steps:
1. Install Express:
npm install express
2. Create a Basic Server:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, Express!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
This code creates a server that listens on port 3000 and responds with "Hello, Express!" at the
root URL.
Express Routing
Defines how the application responds to client requests for specific endpoints and HTTP
methods.
Example:
app.get('/users', (req, res) => {
res.send('List of users');
});
app.post('/users', (req, res) => {
res.send('User created');
});
Routes can be grouped using express.Router() for modularity.
Implementing MVC in Express
Model: Handles data and business logic (e.g., database models).
View: Manages the user interface (e.g., EJS, Pug templates).
Controller: Handles incoming requests, interacts with models, and sends responses.
Example Structure:
/models/user.js
/controllers/userController.js
/views/user.ejs
/app.js
This separation improves code organization and maintainability.
6. Middleware, Template Engines, and Error Handling in Express
Middleware
Middleware functions have access to the request (req), response (res), and the next middleware
in the cycle.
Uses:
Logging
Authentication
Parsing request bodies
Error handling
Example:
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
Using Template Engines
Template engines generate dynamic HTML by combining templates with data.
Popular Engines:
EJS
Pug
Handlebars
Example with EJS:
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', { title: 'Home Page' });
});
Error Handling
Express uses error-handling middleware with four arguments: (err, req, res, next).
Example:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
Centralized error handling improves reliability and debugging.
7. API Handling, Debugging, Process Managers, Security & Deployment
API Handling
Express is widely used to build RESTful APIs, handling JSON data, query parameters, and
different HTTP methods.
Example:
app.use(express.json());
app.post('/api/users', (req, res) => {
const user = req.body;
// Save user logic here
res.status(201).json(user);
});
Debugging
Use console.log() for simple debugging.
Use Node.js built-in debugger (node inspect).
Use tools like nodemon for automatic server restarts.
Use the debug npm module for selective logging.
Using Process Managers
PM2 is a popular process manager for Node.js applications. It keeps apps running, manages
logs, and enables clustering.
Example Commands:
pm2 start app.js
pm2 monit
pm2 restart app
Security & Deployment
Security Best Practices:
Use HTTPS for secure communication.
Sanitize and validate user input.
Use Helmet middleware to set secure HTTP headers.
Manage authentication and authorization securely.
Keep dependencies updated.
Deployment:
Deploy Node.js apps on cloud platforms (AWS, Heroku, DigitalOcean).
Use process managers and reverse proxies (like Nginx) for stability and scalability.
Monitor performance and errors.
8. Developing Template Engines in Express.js
Introduction
Template engines generate dynamic HTML pages by combining templates with data. Express.js
supports popular engines like EJS, Pug, and Handlebars, but you can also create custom
engines.
What is a Template Engine?
A template engine takes a template file (HTML with placeholders) and data, producing final
HTML by replacing placeholders with actual data.
Example Template:
<h1>Welcome, <%= userName %>!</h1>
Rendered with { userName: 'Alice' } produces:
<h1>Welcome, Alice!</h1>
Why Develop a Custom Template Engine?
To support unique syntax or format.
To optimize rendering for specific use cases.
To learn how templating works internally.
To add features not available in existing engines.
How to Develop and Integrate a Custom Template Engine in Express
Express allows you to register a custom template engine using app.engine().
Step-by-Step Guide
1. Create a Simple Template Engine Function
const fs = require('fs');
function simpleTemplateEngine(filePath, options, callback) {
fs.readFile(filePath, 'utf-8', (err, content) => {
if (err) return callback(err);
// Replace {{variable}} placeholders with actual data
let rendered = content.replace(/{{\\s*(\\w+)\\s*}}/g, (match, key) => {
return options[key] || '';
});
return callback(null, rendered);
});
}
2. Register the Engine in Express
const express = require('express');
const app = express();
// Register the engine for .tpl files
app.engine('tpl', simpleTemplateEngine);
// Set the view engine to .tpl files
app.set('view engine', 'tpl');
app.set('views', './views'); // Folder where templates are stored
app.get('/', (req, res) => {
res.render('index', { userName: 'Alice' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
3. Create a Template File
Create views/index.tpl:
<!DOCTYPE html>
<html>
<head>
<title>Simple Template Engine</title>
</head>
<body>
<h1>Welcome, {{ userName }}!</h1>
</body>
</html>
When you visit http://localhost:3000/, the server will render the template and replace {{
userName }} with Alice.
How This Works
Express calls your simpleTemplateEngine function for .tpl files.
The function reads the template file asynchronously.
It replaces all {{ variable }} placeholders with values from the options object.
The rendered HTML is passed back to Express, which sends it as the HTTP response.
Enhancing Your Template Engine
You can extend the simple engine by adding:
Support for loops and conditionals.
Escaping HTML to prevent XSS attacks.
Caching compiled templates for performance.
More complex syntax parsing.
Most developers use established engines (like EJS or Pug) for advanced features.
Summary
Node.js and Express.js together provide a robust platform for building scalable, high-
performance web applications and APIs. Understanding their architecture, modules, process
model, middleware, routing, template engines, and security practices is essential for developing
reliable and maintainable applications [1] .
⁂
1. unit-3.pdf