NODE JSNEW
NODE JSNEW
1. Introduction to Node.js
What is Node.js?
Runtime environment
Advantages of Node.js
Features of Node.js
2. Node.js Architecture
npm init
npm vs. npx
Understanding package.json and package-lock.json
Dev dependencies vs. dependencies
npm start
npm publish
.npmrc file
Scaffolding (e.g., express-generator)
Introduction to Express.js
Features of Express.js
Routing in Express.js
o express.Router()
o Router.all
o Dynamic routing
o Router chaining
o Query parameters vs. URL parameters
o Handling static files
Alternatives to Express.js (e.g., Koa, Hapi, Fastify)
Middleware in Node.js
o Application-level vs. Router-level middleware
o Common middlewares (e.g., express.json, express.urlencoded)
o Error-handling middleware
MVC (Model-View-Controller) architecture
View engines (e.g., EJS, Handlebars)
Session and cookies
7. Advanced Express.js
What is Node.js?
Runtime environment
A runtime environment is a platform that provides the necessary tools and libraries to run
programs written in a specific language. For Node.js, the runtime environment includes:
V8 JavaScript Engine: This engine compiles JavaScript code into machine code, making it
fast and efficient.
Node.js APIs: These are built-in modules that provide functionalities like file system access,
networking, and more.
Event Loop: Node.js uses an event-driven, non-blocking I/O model, which allows it to
handle multiple operations concurrently without waiting for any single operation to
complete
Advantages of Node.js
o High Performance: Node.js is built on the V8 engine, which makes it very fast.
o Scalability: Its event-driven architecture allows it to handle many connections
simultaneously.
o Single Programming Language: You can use JavaScript for both frontend and
backend development.
o Large Ecosystem: The Node Package Manager (npm) provides access to thousands
of libraries and tools.
Features of Node.js
2. Node.js Architecture
Core modules are built-in modules that come with Node.js. They provide essential
functionalities without needing to install additional packages. Some important core
modules include:
Buffer class
The Buffer class in Node.js is used to handle binary data directly. Unlike JavaScript strings,
buffers are raw memory allocations outside the V8 heap.They are useful for dealing with
binary data, such as reading files or handling network packets
Event-driven programming
Node concurrency
Node.js handles concurrency using an event-driven, non-blocking I/O model. This means
it can handle multiple operations simultaneously without waiting for any single operation
to complete. This is achieved through asynchronous programming, where tasks are
executed in the background, and callbacks are used to handle the results
The event loop is a core part of Node.js that allows it to perform non-blocking I/O
operations. Here’s a breakdown:
Event Loop: Continuously checks for and executes tasks from the event queue.
Microtasks: Tasks that need to be executed immediately after the current operation,
like promises.
process.nextTick: A special microtask that executes before other microtasks
Libuv is a library that Node.js uses to handle asynchronous operations. It provides a thread
pool to handle tasks that cannot be executed asynchronously by the event loop, such as
file system operations. This allows Node.js to perform non-blocking I/O operations
efficiently
Garbage collection
npm init
npm init is a command used to create a new package.json file for your Node.js
project. This file contains metadata about your project, such as its name, version,
description, and dependencies. Running npm init will prompt you to enter this
information step-by-step.
You can also use npm init -y to create a package.json file with default values.
npm: Stands for Node Package Manager. It is used to install, update, and manage packages
(libraries) in your Node.js projects.
npx: Stands for Node Package Execute. It is used to run Node.js packages without installing
them globally. This is useful for running one-off commands or tools.
1. package.json: This file contains metadata about your project and lists the dependencies
your project needs to run. It also includes scripts for common tasks like starting the server
or running tests.
2. package-lock.json: This file is automatically generated and ensures that the exact same
versions of dependencies are installed every time. It locks down the versions of all installed
packages, including nested dependencies.
1. Dependencies: These are packages required for your application to run in production. They
are listed under the dependencies section in package.json.
a. npm install express
2. Dev Dependencies: These are packages needed only during development, such as testing
frameworks or build tools. They are listed under the devDependencies section.
a. npm install --save-dev jest
npm start
o npm start is a command used to run the start script defined in
your package.json. If no start script is defined, it defaults to running node
server.js.
{
"scripts": {
"start": "node index.js"
}
}
npm publish
npm publish is a command used to publish your package to the npm registry,
making it available for others to install and use.
.npmrc file
The .npmrc file is used to configure npm settings for your project or globally. You can set
registry URLs, authentication tokens, and other settings.
Scaffolding tools like express-generator help you quickly set up a new project with a
predefined structure. This saves time and ensures consistency .
What is Express.js
Express.js is a minimalist web framework for Node.js. It simplifies the process of building
web applications and APIs by providing a robust set of features and utilities. Essentially,
Express.js allows you to handle HTTP requests and responses with ease, making it a popular
choice for server-side development in JavaScript.
Features of Express.js
Routing in Express.js
o express.Router()
o Router.all
Router.all is a method that handles all HTTP methods (GET, POST, PUT, DELETE,
etc.) for a specific route. It’s useful for middleware that should apply to all types of
requests
o Dynamic routing
Dynamic routing allows you to define routes with parameters that can change.
These parameters are defined using a colon (:) and can be accessed
via req.params.
o Router chaining
Router chaining allows you to chain route handlers for a single route. This is
useful for applying multiple middleware functions in sequence.
Query Parameters: Passed in the URL after the question mark (?) and are used for
optional data. Accessed via req.query
Express.js can serve static files (like images, CSS, JavaScript) using
the express.static middleware. This is useful for serving assets required by
your frontend
Middleware in Node.js
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 perform various tasks such as modifying the request or response objects, ending the request-
response cycle, or calling the next middleware function.
// Router-level middleware
router.use((req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
});
Common Middlewares
app.use(express.json());
Error-Handling Middleware
o Error-handling middleware is defined with four parameters: err, req, res, and next. It is
used to catch and handle errors that occur during the request-response cycle.
JavaScript
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
Example of Error-Handling Middleware
const express = require('express');
const app = express();
// Error-handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Model: Manages the data and business logic. It interacts with the database and handles data-
related operations.
View: Handles the presentation layer. It displays the data to the user and collects user input.
Controller: Acts as an intermediary between the Model and the View. It processes user input,
interacts with the Model, and updates the View accordingly.
This separation helps in organizing code, making it easier to manage and scale.
EJS (Embedded JavaScript): Allows you to embed JavaScript code within HTML. It is simple and
easy to use.
Handlebars: A logic-less templating engine that focuses on simplicity. It uses placeholders and
helpers to generate dynamic content.
{{#if loggedIn}}
<p>Welcome, {{username}}!</p>
{{else}}
<a href="/login">Login</a>
{{/if}}
Both view engines help in creating dynamic web pages by integrating server-side data with HTML
templates.
Session: A session stores data on the server for a specific user and is used to maintain state
across multiple requests. Sessions are temporary and expire when the user closes the browser or
logs out.
Cookies: Cookies are small text files stored on the user’s computer by the web browser. They can
persist across multiple sessions and are used to store user preferences, login information, and
other data.
Differences:
Storage: Sessions are stored on the server, while cookies are stored on the client-side.
Security: Sessions are generally more secure as they are stored on the server.
Persistence: Cookies can persist across multiple sessions, while sessions expire when the browser
is closed.
o HTTP (Hypertext Transfer Protocol): Used for transferring data over the web. Data sent
via HTTP is not encrypted, making it vulnerable to interception.
o HTTPS (Hypertext Transfer Protocol Secure): Similar to HTTP but uses encryption
(SSL/TLS) to secure data transfer, protecting it from eavesdropping and tampering.
HTTP Methods (GET, POST, PUT, PATCH, DELETE, OPTIONS)
o Request Headers: Sent by the client to provide information about the request or the client
itself (e.g., Content-Type, Authorization).
o Response Headers: Sent by the server to provide information about the response
(e.g., Content-Length, Set-Cookie).
CORS is a mechanism that allows a server to specify which origins (domains) can access its
resources. It uses HTTP headers to manage cross-origin requests and includes a preflight
request to check permissions.
res.send: Sends a response to the client and ends the response process.
res.send('Hello, World!');
res.write('Hello, ');
res.write('World!');
res.end();
res.end: Ends the response process. Can optionally send data before ending.
res.end('Goodbye!');
res.redirect
Query Parameters: Passed in the URL after the ? symbol and accessed via req.query.
// URL: /search?term=javascript
app.get('/search', (req, res) => {
const term = req.query.term;
res.send(`Search term: ${term}`);
});
Path Parameters: Part of the URL path and accessed via req.params.
// URL: /users/123
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`User ID: ${userId}`);
});
The OPTIONS method is used to describe the communication options for the target resource.
Preflight requests are sent by browsers to check if the server allows the actual request method
(like POST or DELETE) from a different origin.
res.sendFile('/path/to/file');
res.download('/path/to/file');
Middleware Types (Application, Router, Error-Handling)
const fs = require('fs');
const readableStream = fs.createReadStream('file.txt');
readableStream.on('data', (chunk) => {
console.log(chunk);
});
Transform Streams: A type of duplex stream that can modify the data as it is read or written.
Stream Piping
Stream piping allows you to connect multiple streams together, passing data from one stream to
another.
const fs = require('fs');
const readableStream = fs.createReadStream('input.txt');
const writableStream = fs.createWriteStream('output.txt');
readableStream.pipe(writableStream);
Event-Driven Architecture
Event-driven architecture (EDA) is a design pattern where systems react to events. An event is a
significant change in state, like a user clicking a button. EDA allows systems to be more
responsive and scalable.
In Node.js, the EventEmitter class allows you to create, emit, and handle events.
// Event handler
eventEmitter.on('greet', (name) => {
console.log(`Hello, ${name}!`);
});
// Emit event
eventEmitter.emit('greet', 'Alice');
function fetchData(callback) {
setTimeout(() => {
callback('Data fetched');
}, 1000);
}
fetchData((data) => {
console.log(data);
});
fetchData()
.then((data) => {
console.log(data);
return processData(data);
})
.then((processedData) => {
console.log(processedData);
})
.catch((error) => {
console.error(error);
});
Promisify
promisify converts callback-based functions to return promises.
readFile('file.txt', 'utf8')
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
Callbacks
Callbacks are functions passed as arguments to other functions to be executed later.
function doSomething(callback) {
setTimeout(() => {
callback('Done');
}, 1000);
}
doSomething((message) => {
console.log(message);
});
.
async/await
PUT: Used to update a resource. It is idempotent, meaning multiple identical requests will have
the same effect as a single request. It typically replaces the entire resource.
PATCH: Used for partial updates to a resource. It is not necessarily idempotent, meaning multiple
identical requests might have different effects.
var: Function-scoped. Variables declared with var are accessible within the entire function.
function example() {
var x = 10;
if (true) {
var x = 20; // Same variable
console.log(x); // 20
}
console.log(x); // 20
}
let: Block-scoped. Variables declared with let are only accessible within the nearest enclosing
block.
function example() {
let x = 10;
if (true) {
let x = 20; // Different variable
console.log(x); // 20
}
console.log(x); // 10
}
URL Encoding
URL encoding converts characters into a format that can be transmitted over the Internet. It
replaces unsafe ASCII characters with a % followed by two hexadecimal digits.
body-parser: Middleware to parse incoming request bodies. It was commonly used before
Express 4.16.0.
express.json(): Built-in middleware to parse JSON payloads.
app.use(express.json());
Cookies: Small text files stored on the client-side. They can persist across sessions.
Sessions: Store data on the server-side and are used to maintain state across multiple requests.
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
readFileSync: Synchronously reads the contents of a file.
These methods from the child_process module allow you to create and manage child
processes:
fork(): Creates a new Node.js process. Useful for running multiple instances of a Node.js
application.
Child Processes
A child process is a process created by another process (the parent process). In Node.js, child
processes can be used to run multiple tasks concurrently, improving performance and scalability.
Clustering in Node.js
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello, world!');
}).listen(8000);
}
process.nextTick vs setImmediate
process.nextTick(): Executes code after the current operation completes, before I/O tasks.
process.nextTick(() => {
console.log('Next tick');
});
setImmediate(): Executes code after the current event loop phase, following I/O tasks.
setImmediate(() => {
console.log('Immediate');
});
# Install PM2
npm install pm2 -g
# Start an application
pm2 start app.js
# Monitor applications
pm2 monit
# Start REPL
node
# Example commands
> 2 + 2
4
> console.log('Hello, world!')
Hello, world!
emitter.on('event', () => {
console.log('An event occurred!');
});
emitter.emit('event');
Child Processes: Use child processes to run tasks concurrently, improving performance.
Example:
const io = require('socket.io')(3000);
Example:
CSRF Protection
Cross-Site Request Forgery (CSRF) attacks trick users into performing actions they didn’t
intend. To protect against CSRF, use tokens that are unique to each session and validate them on
the server.
Example using csurf middleware:
Encryption: Converts data into a format that can be reversed with a key. Used for data in transit
and storage.
Hashing: Converts data into a fixed-size string of characters, which cannot be reversed. Used for
storing passwords.
Example:
Cron jobs are scheduled tasks that run at specific intervals. They are useful for automating
repetitive tasks like backups, sending emails, etc.
# Example of a cron job that runs every day at midnight
0 0 * * * /path/to/your/script.sh
Practical Examples
const fs = require('fs');
const date = new Date().toISOString();
fs.writeFile('log.txt', `Log entry at ${date}\n`, { flag: 'a' }, (err) => {
if (err) throw err;
console.log('Log saved!');
});
Blocking Code: Operations that block further execution until they complete. Example: reading a
file synchronously.
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8'); // Blocks here until file
is read
console.log(data);
Non-Blocking Code: Operations that allow the program to continue executing while they
complete. Example: reading a file asynchronously.
Optional Chaining: Safely accesses deeply nested properties without causing errors if a property
is undefined or null.
Thread Pool: Node.js uses a thread pool (via libuv) to handle tasks that cannot be performed
asynchronously by the event loop, such as file system operations.
Async Operations: These operations run in the background, allowing the main thread to
continue executing other tasks. Callbacks, promises, and async/await are used to handle the
results of these operations.
Trace: Tools like node --trace-events and node --inspect help trace and debug
performance issues.
Performance Tuning: Techniques include profiling your application, optimizing code, using
efficient algorithms, and monitoring resource usage to identify bottlenecks.
// Custom middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // Pass control to the next middleware
};
app.use(logger);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Client Sends Request: A client (like a web browser) sends an HTTP request to a server. This request
includes a method (GET, POST, etc.), a URL, headers, and sometimes a body.
Server Processes Request: The server receives the request, processes it, and determines the
appropriate response.
Server Sends Response: The server sends back an HTTP response, which includes a status code
(e.g., 200 OK), headers, and sometimes a body (like HTML content).
Client Receives Response: The client receives the response and processes it, displaying the
content to the user or performing other actions.
Cookies: Small text files stored on the client’s device. They can persist across sessions and are
used to store user preferences, session tokens, etc.
// Setting a cookie
res.cookie('name', 'value', { maxAge: 900000, httpOnly: true });
Sessions: Store data on the server side and use a session ID stored in a cookie to track the user.
Sessions are more secure as the data is not stored on the client.
URL Fragments: Part of a URL that follows a # symbol. Used to navigate to a specific section of a
page.
GET Requests: Typically, GET requests do not have a body. They are used to retrieve data.
POST Requests: Used to send data to the server.
emitter.on('event', () => {
console.log('An event occurred!');
});
emitter.emit('event');
const fs = require('fs');
const readStream = fs.createReadStream('largefile.txt');
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});
Clustering: Use the cluster module to run multiple instances of your application.
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello, world!');
}).listen(8000);
}
Profiling: Use tools like node --prof to analyze your application’s performance.
Trace: Use the trace module to track function calls and execution times.
# Start REPL
node
# Example commands
> 2 + 2
4
> console.log('Hello, world!')
Hello, world!
1. Event Loop: The mechanism that allows Node.js to perform non-blocking I/O operations. It
handles asynchronous operations by using callbacks, promises, and async/await.
2. Non-blocking I/O: Node.js uses non-blocking I/O to handle multiple operations concurrently
without waiting for each to complete.
3. CommonJS Module System: Node.js uses CommonJS for module management. You
use require to import modules and module.exports to export them.
4. Global Objects: Objects like process, global, and console are available globally in Node.js.
Practical Examples
// Custom middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
app.use(logger);
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
package.json: This file contains metadata about your project and its dependencies.
{
"name": "my-node-app",
"version": "1.0.0",
"description": "A simple Node.js app",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
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.
Example:
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Handling Complex Routing Scenarios
app.use('/api', router);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
emitter.on('event', () => {
console.log('An event occurred!');
});
emitter.emit('event');