Q)What is Express.js?
Express.js (or simply Express) is the most popular Node.js web application framework, designed for building web
applications and APIs.
It's often called the de facto standard server framework for Node.js.
Key Characteristics:
Minimal and flexible
Unopinionated (you decide how to structure your app)
Lightweight and fast
Extensible through middleware
Huge ecosystem of plugins and extensions
Getting Started with Express
Express can be added to any Node.js project. Here's how to get started with a new Express application.
Prerequisites
Before you begin, make sure you have:
Node.js installed (v14.0.0 or later recommended)
npm (comes with Node.js) or yarn
A code editor (VS Code, WebStorm, etc.)
Installing Express
To use Express in your Node.js application, you first need to install it:
npm install express
To install Express and save it in your package.json dependencies:
npm install express --save
Hello World Example
Let's create a simple "Hello World" application with Express.
This example demonstrates the basic structure of an Express application.
Key Components:
Importing the Express module
Creating an Express application instance
Defining routes
Starting the server
const express = require('express');
const app = express();
const port = 8080;
// Define a route for GET requests to the root URL
app.get('/', (req, res) => {
res.send('Hello World from Express!');
});
// Start the server
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
Run example »
Save this code in a file named app.js and run it with Node.js:
node app.js
Then, open your browser and navigate to http://localhost:8080 to see the "Hello World" message.
Q)Express routing is a fundamental feature of the Express.js web framework (built on Node.js) that lets you define
how your application responds to client requests at specific endpoints (routes) and HTTP methods (GET, POST,
etc.).
🔹 Basic Structure of Routing in Express
js
CopyEdit
const express = require('express');
const app = express();
const port = 3000;
// GET request to homepage
app.get('/', (req, res) => {
res.send('Hello, world!');
});
// POST request to /submit
app.post('/submit', (req, res) => {
res.send('Form submitted');
});
// Route with URL parameter
app.get('/users/:userId', (req, res) => {
res.send(`User ID: ${req.params.userId}`);
});
app.listen(port, () => {
console.log(`App listening on http://localhost:${port}`);
});
🔹 Route Methods
Express supports routing methods corresponding to HTTP methods:
app.get(path, handler)
app.post(path, handler)
app.put(path, handler)
app.delete(path, handler)
app.all(path, handler) – handles all HTTP methods
🔹 Route Parameters
Route parameters are named URL segments:
js
CopyEdit
app.get('/books/:bookId', (req, res) => {
const bookId = req.params.bookId;
res.send(`Book ID: ${bookId}`);
});
🔹 Middleware and Route Chaining
You can chain route handlers using middleware:
js
CopyEdit
const logRequest = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
app.get('/about', logRequest, (req, res) => {
res.send('About page');
});
🔹 Express Router
You can modularize routes using express.Router():
js
CopyEdit
// userRoutes.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => res.send('User list'));
router.get('/:id', (req, res) => res.send(`User ID: ${req.params.id}`));
module.exports = router;
// app.js
const express = require('express');
const app = express();
const userRoutes = require('./userRoutes');
app.use('/users', userRoutes);
Q)Middleware in Express
Middleware functions are the backbone of Express applications.
They have access to:
The request object (req)
The response object (res)
The next middleware function in the stack (next)
Middleware can:
Execute any code
Modify request and response objects
End the request-response cycle
Call the next middleware in the stack
Built-in Middleware
Express includes several useful middleware functions:
express.json() - Parse JSON request bodies
express.urlencoded() - Parse URL-encoded request bodies
express.static() - Serve static files
express.Router() - Create modular route handlers
const express = require('express');
const app = express();
const port = 8080;
// Middleware to parse JSON request bodies
app.use(express.json());
// Middleware to parse URL-encoded request bodies
app.use(express.urlencoded({ extended: true }));
// Middleware to serve static files from a directory
app.use(express.static('public'));
// POST route that uses JSON middleware
app.post('/api/users', (req, res) => {
// req.body contains the parsed JSON data
console.log(req.body);
res.status(201).json({ message: 'User created', user: req.body });
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
Q)Error Handling in Express
Error handling in Express is done through special middleware functions that have four arguments:
(err, req, res, next).
Key Points:
Error-handling middleware must have four arguments
It should be defined after other app.use() and route calls
You can have multiple error-handling middleware functions
Use next(err) to pass errors to the next error handler
Express comes with a default error handler to catch errors that occur during request processing:
const express = require('express');
const app = express();
const port = 8080;
// Route that may throw an error
app.get('/error', (req, res) => {
// Simulating an error
throw new Error('Something went wrong!');
});
// Route that uses next(error) for asynchronous code
app.get('/async-error', (req, res, next) => {
// Simulating an asynchronous operation that fails
setTimeout(() => {
try {
// Something that might fail
const result = nonExistentFunction(); // This will throw an error
res.send(result);
}
catch (error) {
next(error); // Pass errors to Express
}
}, 100);
});
// Custom error handling middleware
// Must have four parameters to be recognized as an error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
Q) API handling
API handling in Node.js primarily involves setting up a server to listen for incoming HTTP requests, processing those
requests, and sending back appropriate responses. The most common and recommended approach for building
APIs in Node.js is to use the Express.js framework due to its flexibility and robust features.
Core Concepts of API Handling with Express.js:
Setting up the Server:
o Initialize a new Node.js project using npm init -y.
o Install Express.js: npm install express.
o Create a server file (e.g., server.js or app.js) and set up an Express application to listen on a
specific port.
JavaScript
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Middleware:
Middleware functions are executed in the order they are defined before the final route handler.
app.use(express.json()); is crucial for parsing incoming JSON request bodies.
Other common middleware includes cors for handling Cross-Origin Resource Sharing, and
custom middleware for authentication, logging, or error handling.
Defining Routes:
Routes define the API endpoints and the HTTP methods (GET, POST, PUT, DELETE,
PATCH) they handle.
Each route takes a path and a callback function (route handler) that receives req (request)
and res (response) objects.
JavaScript
// GET request to retrieve data
app.get('/api/users', (req, res) => {
// Logic to fetch users from a database
res.json({ message: 'List of users' });
});
// POST request to create data
app.post('/api/users', (req, res) => {
const newUser = req.body;
res.status(201).json({ message: 'User created', user: newUser });
});
app.put('/api/users/:id', (req, res) => {
const userId = req.params.id;
const updatedData = req.body;
res.json({ message: `User with ID ${userId} updated` });
});
app.delete('/api/users/:id', (req, res) => {
const userId = req.params.id;
res.status(204).send();
});
Handling Request and Response:
req object: Contains information about the incoming request, including req.body (parsed
request body), req.params (route parameters), req.query (query parameters), req.headers, etc.
res object: Used to send responses back to the client. Common methods include:
res.send(): Sends various types of responses.
res.json(): Sends a JSON response.
res.status(): Sets the HTTP status code.
res.end(): Ends the response process.
Q)Error Handling:
Implement error-handling middleware to catch and process errors gracefully, sending
appropriate error responses to the client.
By following these principles and utilizing the features of Express.js, developers can effectively handle API requests
and build robust and scalable web services in Node.js.
Q) Debugging in Node.js can be done in several effective ways, ranging from basic console.log() statements to
using built-in or advanced tools like the Node.js debugger, Chrome DevTools, or VS Code. Here’s a breakdown:
🔧 1. Using console.log() (Basic but Effective)
js
CopyEdit
const sum = (a, b) => {
console.log('a:', a, 'b:', b); // Debug input
return a + b;
};
🐞 2. Using the Built-in Node Debugger
You can launch Node with the inspect or inspect-brk flag:
bash
CopyEdit
node inspect app.js
Or pause execution at the first line:
bash
CopyEdit
node --inspect-brk app.js
In the debugger:
Type n to go to the next line
Type c to continue execution
Type repl to enter an interactive shell
🧠 3. Using Chrome DevTools for Node.js
Launch your app like this:
bash
CopyEdit
node --inspect app.js
Then open Chrome and go to:
arduino
CopyEdit
chrome://inspect
Click "Inspect" next to your app to use Chrome DevTools (breakpoints, variable watch, call stack).
🧩 4. Debugging in Visual Studio Code (VS Code)
1. Open your Node.js project in VS Code.
2. Go to the Run and Debug panel (Ctrl+Shift+D or click the play icon).
3. Click "create a launch.json file" and select Node.js.
4. Example launch.json:
json
CopyEdit
{
"type": "node",
"request": "launch",
"name": "Debug App",
"program": "${workspaceFolder}/app.js"
}
5. Set breakpoints, then click the green play button to start debugging.
🧰 5. Third-Party Debugging Tools
nodemon – Auto restarts the server on file changes.
node-inspector (deprecated, use built-in now)
Logging libraries like debug, winston, pino for structured logging.
🧼 6. Best Practices
Avoid excessive console.log in production.
Use environment-based logging levels.
Use .env and NODE_ENV to toggle debugging modes.
Q) Developing template engines in Node.js, particularly with the Express.js framework, involves integrating a
chosen templating library to dynamically generate HTML content.
1. Installation and Setup:
Install a Template Engine: Choose a template engine like EJS, Pug (formerly Jade), or Handlebars and
install it using npm. For example, to install EJS:
Code
npm install ejs
Configure Express.js: In your main Express.js application file (e.g., app.js), set the view
engine and views directory. The views directory is where your template files will reside.
JavaScript
const express = require('express');
const path = require('path');
const app = express();
app.set('view engine', 'ejs'); // Set EJS as the view engine
app.set('views', path.join(__dirname, 'views')); // Specify the views directory
2. Creating Templates:
Create template files with the appropriate extension (e.g., .ejs for EJS, .pug for Pug) within the
designated views directory.
Use the template engine's specific syntax to embed dynamic data and logic. For example, in EJS, you
might use <%= variable %> to display data.
3. Rendering Templates:
In your Express.js route handlers, use the res.render() method to render a template and pass data to it as
an object.
JavaScript
app.get('/', (req, res) => {
const data = {
title: 'My Node.js App',
message: 'Welcome to the homepage!'
};
res.render('index', data); // Renders 'index.ejs' and passes the 'data' object
});
4. Example (using EJS):
views/index.ejs.
Code
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= message %></h1>
</body>
</html>
5. Running the Application:
Start your Node.js application (e.g., node app.js) and access the defined route in your browser. The
template engine will process the template, inject the dynamic data, and send the resulting HTML to the client.
Implementing MVC (Model-View-Controller) in Express.js
The MVC architectural pattern helps organize your Express.js application by separating concerns into three distinct
parts:
1. Model
Role: Handles data and business logic, interacting with the database to retrieve, store, and manipulate
data.
Example: A User model might define the structure of user data (e.g., username, email, password) and
provide methods for operations like creating a new user or finding users in the database.
Best Practices:
Place models in a dedicated folder (e.g., /models).
Utilize ORMs like Mongoose for MongoDB or Sequelize for relational databases to simplify data
interactions.
Implement data validation and other business logic within the model.
2. View
Role: Handles the presentation layer, displaying data to the user and interacting with the Controller based
on user input.
Example: An EJS template (index.ejs) might display a list of tasks, receiving the task data from the
Controller.
Best Practices:
Store views in a dedicated folder (e.g., /views).
Employ templating engines like EJS, Pug, or Handlebars to dynamically render HTML.
Minimize complex logic within views, focusing primarily on presentation.
3. Controller
Role: Acts as the intermediary between the Model and View, handling incoming requests, interacting with
the Model to retrieve or update data, and selecting the appropriate View for rendering the response.
Example: A taskController.js might have functions like getAllTasks (fetching tasks from the Model)
and createTask (receiving data from a POST request and updating the Model).
Best Practices:
Keep controllers lean; delegate complex business logic to the model or dedicated service
layers.
Implement controllers in a dedicated folder (e.g., /controllers).
Handle request processing, data validation (sometimes done in model), and error management
within the controller.
Implementation steps
1. Project Setup:
1. Initialize your project using npm init -y.
2. Install necessary dependencies like Express, a templating engine (e.g., EJS), and a database
library/ORM (e.g., Mongoose).
File Structure:
1. Create a well-organized folder structure (e.g., /models, /views, /controllers, /routes) to separate
your components.
Model Configuration:
1. Define your data models using an ORM or a database library.
Controller Implementation:
1. Develop controllers to handle request logic, interacting with your models.
View Setup:
1. Create view templates (e.g., EJS files) to render data dynamically.
Route Definition:
1. Use Express Router to define routes and map them to your controller actions.
Application Integration:
1. In your main application file (e.g., app.js or server.js), configure middleware
(like express.json() for parsing request bodies) and connect your routes to the application instance.
By following these steps and the best practices outlined, you can effectively implement the MVC pattern in your
Express.js applications, leading to more organized, maintainable, and scalable code bases.
Unit-4
Q) designing uri in restful web services
In RESTful web services, URIs should be designed to represent resources, not actions. They should be clear,
concise, and predictable, using nouns to represent resources and HTTP methods to define actions performed on
those resources. Key principles include using plural nouns for collections, hyphens for readability, and avoiding
verbs or implementation details in the URI.
Here's a more detailed breakdown:
1. Focus on Resources, Not Actions:
Resources:
Represent data or objects in your application (e.g., users, products, orders).
HTTP Methods (verbs):
Use methods like GET, POST, PUT, DELETE, and PATCH to act on those resources.
Example:
Instead of /getUsers or /fetchUsers, use /users to represent the collection of users.
2. Structure and Conventions:
Plural Nouns: Use plural nouns for collections (e.g., /users, /products) and singular nouns for individual
items (e.g., /users/123, /products/456).
Hierarchical Relationships: Use forward slashes to represent hierarchical relationships
(e.g., /users/123/orders to represent orders for a specific user).
Hyphens for Readability: Use hyphens (-) to separate words in resource names (e.g., /product-
categories, /shipping-addresses).
Lowercase: Prefer lowercase letters for all parts of the URI.
No File Extensions: Avoid including file extensions (e.g., .html, .php) in the URI.
Query Parameters: Use query parameters for filtering, sorting, or pagination (e.g., /products?
category=electronics&sort=price).
3. Examples:
Poor: http://example.com/users/getUserById/123 (contains a verb and implementation detail)
Good: http://example.com/users/123 (resource is /users, ID is 123, GET method retrieves it)
Poor: http://example.com/products/createProduct (contains a verb)
Good: http://example.com/products (POST method creates a new product)
4. Additional Considerations:
Backward Compatibility: If you need to change a URI, use a redirect (HTTP status code 301 or 302) to
point the old URI to the new one.
URI Length: Keep URI segments short and avoid excessively long URIs.
Consistent Subdomains: Use consistent subdomain names for your APIs.
5. Benefits of Good URI Design:
Improved Usability: Makes APIs easier to understand and use.
Increased Discoverability: Clear URIs help users understand the API's structure and functionality.
Enhanced Maintainability: Easier to maintain and evolve the API over time.
Better Scalability: Consistent and well-structured URIs can improve caching and scalability.
Q) Conditional requests in RESTful web services
Conditional requests in RESTful web services allow clients to make requests that are processed only if certain
conditions are met, improving efficiency and reducing unnecessary data transfer. This is especially useful for
caching, concurrency control, and optimizing bandwidth.
🔹 Why Use Conditional Requests?
Prevents sending unchanged data (saves bandwidth).
Avoids overwriting updated resources (helps with concurrency).
Supports caching mechanisms.
🔹 Key HTTP Headers for Conditional Requests
1. ETag (Entity Tag)
An identifier for a specific version of a resource, often a hash or a version string.
2. Last-Modified
Timestamp indicating when the resource was last changed.
🔹 Types of Conditional Requests
HTTP Header Used With Purpose Success Code Fail Code
If-None-Match GET Return only if resource changed 200 OK / 304
If-Modified-Since GET Return only if modified 200 OK / 304
If-Match PUT/DELETE Update only if matches ETag 204 No Content 412 Precondition Failed
If-Unmodified-Since PUT Update only if not modified 204 No Content 412 Precondition Failed
Q)What is ReactDOM ?
The ReactDOM in React is responsible for rendering the elements or Components in the actual DOM of the
web page. It is a package in React that provides DOM-specific methods that can be used at the top level of a
web app to enable an efficient way of managing DOM elements of the web page. ReactDOM provides the
developers with an API containing the various methods to manipulate DOM.
How to use ReactDOM ?
To use the ReactDOM in any React web app we must first install the react-dom package in our project. To install
the react-dom package use the following command.
// Installing
npm i react-dom
After installing the package use the following command to import the package in your application file
// Importing
import ReactDOM from 'react-dom'
After installing react-dom it will appear in the dependenices in package.json file like:
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
}
Important Methods of ReactDOM
render(): This is one of the most important methods of ReactDOM. This function is used to render a
single React Component or several Components wrapped together in a Component or a div element.
findDOMNode(): This function is generally used to get the DOM node where a particular React
component was rendered. This method is very less used like the following can be done by adding a ref attribute to
each component itself.
unmountComponentAtNode(): This function is used to unmount or remove the React Component that
was rendered to a particular container.
hydrate(): This method is equivalent to the render() method but is implemented while using server-side
rendering.
createPortal(): It allow us to render a component into a DOM node that resides outside the current DOM
hierarchy of the parent component.
Features
ReactDOM.render() replaces the child of the given container if any. It uses a highly efficient diff algorithm
and can modify any subtree of the DOM.
React findDOMNode() function can only be implemented upon mounted components thus Functional
components can not be used in findDOMNode() method.
ReactDOM uses observables thus provides an efficient way of DOM handling.
ReactDOM can be used on both the client-side and server-side.
Use Case
Rendering the elements and react app to the root DOM element.
Hydrating the components rendering on serverside with the client-side intractivity.
Managing the DOM for dynamic user interface.
Q) React components
In React, React components are independent, reusable building blocks in a React application that define what gets
displayed on the UI. They accept inputs called props and return React elements describing the UI. A component is
a building block that encapsulates a piece of the user interface (UI). It defines the structure and behavior of the UI,
either by managing its own state or by receiving data through props and rendering content accordingly.
Components are reusable and can be composed together to build complex UIs in a modular way.
Components can be reused across different parts of the application to maintain consistency and reduce
code duplication.
Components manage how their output is rendered in the DOM based on their state and props.
React loads only the necessary components, ensuring optimized performance.
Only the specific Component updates instead of the whole page.
Types of React Components
There are two primary types of React components:
1. Functional Components
Functional components are simpler and preferred for most use cases. They are JavaScript functions that
return React elements. With the introduction of React Hooks, functional components can also manage state and
lifecycle events.
Stateless or Stateful: Can manage state using React Hooks.
Simpler Syntax: Ideal for small and reusable components.
Performance: Generally faster since they don’t require a 'this' keyword.
function Greet(props) {
return <h1>Hello, {props.name}!</h1>;
}
2. Class Components
Class components are ES6 classes that extend React.Component. They include additional features like state
management and lifecycle methods.
State Management: State is managed using the this.state property.
Lifecycle Methods: Includes methods like componentDidMount, componentDidUpdate, etc.
class Greet extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}