1. Introduction to Express.js
Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for building web and mobile applications. As a lightweight framework, it simplifies the process of handling HTTP requests, routing, middleware, and more, making it a popular choice for building RESTful APIs and single-page applications (SPAs).
2. Setting Up an Express.js Application
Setting up an Express.js application involves a few key steps. You begin by installing Node.js, setting up your project, and installing Express as a dependency.
2.1 Installing Express.js
First, initialize a new Node.js project and install Express.js using npm (Node Package Manager).
2.1.1 Example: Installing Express
npm init -y
npm install express
2.2 Creating a Basic Express Server
Once installed, you can create a simple Express server that listens for HTTP requests on a specified port.
2.2.1 Example: Basic Express Server
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
3. Middleware in Express.js
Middleware functions in Express.js 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. Middleware can execute any code, make changes to the request and response objects, end the request-response cycle, or call the next middleware in the stack.
3.1 Types of Middleware
Express.js has several types of middleware, including:
- Application-Level Middleware: Bound to an instance of the Express app object and executed during every request that matches a specific route.
- Router-Level Middleware: Bound to an instance of the Express
Router
object and executed during requests that match a router's routes. - Error-Handling Middleware: Used to catch and handle errors that occur during the execution of middleware and routes.
- Built-in Middleware: Includes functions like
express.json()
andexpress.static()
, which are provided out of the box. - Third-Party Middleware: Middleware functions provided by the community, such as
morgan
for logging andcors
for enabling Cross-Origin Resource Sharing.
3.2 Creating Custom Middleware
You can create custom middleware functions to perform tasks like logging, authentication, or data validation.
3.2.1 Example: Custom Logging Middleware
const requestTime = (req, res, next) => {
req.requestTime = Date.now();
console.log(`Request received at: ${req.requestTime}`);
next();
};
app.use(requestTime);
4. Routing in Express.js
Routing refers to how an application’s endpoints (URIs) respond to client requests. In Express.js, routing is handled by defining routes using the HTTP methods (GET, POST, PUT, DELETE, etc.) and the paths to which they respond.
4.1 Defining Routes
Routes in Express.js can be defined using the app’s HTTP methods. Each route can specify a callback function to handle the request and send a response.
4.1.1 Example: Basic Routing
app.get('/users', (req, res) => {
res.send('GET request to /users');
});
app.post('/users', (req, res) => {
res.send('POST request to /users');
});
4.2 Route Parameters
Route parameters are named segments of the URL that can be used to capture values and pass them to the route handlers. These parameters are defined using the :
symbol.
4.2.1 Example: Route Parameters
app.get('/users/:userId', (req, res) => {
const userId = req.params.userId;
res.send(`User ID is ${userId}`);
});
4.3 Query Parameters
Query parameters are used to pass data to the server via the URL. They are typically used for filtering, searching, or pagination and are accessed through req.query
.
4.3.1 Example: Handling Query Parameters
app.get('/search', (req, res) => {
const { q } = req.query;
res.send(`Search query is: ${q}`);
});
5. Working with Data in Express.js
Express.js provides multiple ways to handle and manipulate data, whether it’s data from forms, databases, or other sources.
5.1 Parsing JSON and URL-encoded Data
Express.js comes with built-in middleware to parse incoming requests with JSON payloads and URL-encoded data.
5.1.1 Example: Parsing JSON and URL-encoded Data
app.use(express.json()); // Parse JSON bodies
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies
5.2 Connecting to Databases
Express.js does not come with built-in database integration, but it can be easily connected to databases using libraries and ORM (Object-Relational Mapping) tools like Mongoose for MongoDB or Sequelize for SQL databases.
5.2.1 Example: Connecting to MongoDB with Mongoose
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const UserSchema = new mongoose.Schema({
name: String,
email: String,
});
const User = mongoose.model('User', UserSchema);
6. Error Handling in Express.js
Error handling in Express.js is essential for managing runtime errors and ensuring that the application responds appropriately without crashing. Express provides a straightforward way to define error-handling middleware.
6.1 Defining Error-Handling Middleware
Error-handling middleware is similar to other middleware, but it takes four arguments: err
, req
, res
, and next
. This middleware is used to catch and respond to errors that occur in the application.
6.1.1 Example: Basic Error-Handling Middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
6.2 Handling 404 Errors
When a requested resource is not found, a 404 error is returned. Express allows you to define middleware to handle such errors gracefully.
6.2.1 Example: Handling 404 Errors
app.use((req, res, next) => {
res.status(404).send('Sorry, can’t find that!');
});
7. Securing Express.js Applications
Security is a crucial aspect of any web application. Express.js provides several mechanisms and best practices to secure your application against common vulnerabilities and attacks.
7.1 Using Helmet for Security Headers
Helmet is a middleware that helps secure Express.js applications by setting various HTTP headers. These headers can prevent attacks like XSS, clickjacking, and other code injection attacks.
7.1.1 Example: Using Helmet
const helmet = require('helmet');
app.use(helmet());
7.2 Preventing Cross-Site Request Forgery (CSRF)
CSRF is a type of attack where unauthorized commands are transmitted from a user that the web application trusts. Express.js applications can prevent CSRF attacks using middleware like csurf
.
7. 2.1 Example: Implementing CSRF Protection
const csurf = require('csurf');
const csrfProtection = csurf({ cookie: true });
app.use(csrfProtection);
app.get('/form', (req, res) => {
res.send(``);
});
7.3 Input Validation and Sanitization
Validating and sanitizing user input is essential to prevent SQL injection, XSS, and other injection attacks. Express.js does not come with built-in validation, but libraries like express-validator
can be used.
7.3.1 Example: Using express-validator
const { body, validationResult } = require('express-validator');
app.post('/user',
body('email').isEmail(),
body('password').isLength({ min: 5 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Proceed with user creation
res.send('User created');
}
);
8. Templating in Express.js
Templating allows dynamic rendering of HTML pages by embedding JavaScript logic within the HTML. Express.js supports various templating engines like Pug, EJS, and Handlebars to generate dynamic content on the server side.
8.1 Using Pug with Express.js
Pug (formerly known as Jade) is a popular templating engine that uses a clean, whitespace-sensitive syntax to write HTML. It is often used with Express.js to render HTML views dynamically.
8.1.1 Example: Setting Up Pug in Express.js
app.set('view engine', 'pug');
app.get('/profile', (req, res) => {
res.render('profile', { title: 'Profile Page', user: { name: 'John Doe' } });
});
8.2 Using EJS with Express.js
EJS (Embedded JavaScript) is another templating engine that allows you to generate HTML with embedded JavaScript logic. It is simple to use and integrates well with Express.js.
8.2.1 Example: Setting Up EJS in Express.js
app.set('view engine', 'ejs');
app.get('/dashboard', (req, res) => {
res.render('dashboard', { title: 'Dashboard', user: { name: 'Jane Doe' } });
});
9. Deployment of Express.js Applications
Once development is complete, deploying an Express.js application to production requires certain steps to ensure it runs efficiently and securely. Deployment can be done on various platforms, including traditional servers, cloud services, and containerized environments.
9.1 Deploying to Heroku
Heroku is a popular cloud platform that supports Node.js applications. Deploying an Express.js application to Heroku is straightforward and involves a few key steps.
9.1.1 Example: Deploying to Heroku
heroku create
git push heroku main
heroku open
9.2 Using PM2 for Process Management
PM2 is a production process manager for Node.js applications that ensures your application remains running, even after crashes or server reboots. It also helps with load balancing and monitoring.
9.2.1 Example: Setting Up PM2
npm install -g pm2
pm2 start app.js --name "my-app"
pm2 startup
pm2 save
9.3 Containerizing with Docker
Docker allows you to containerize your Express.js application, making it easier to deploy across different environments consistently. By packaging your application and its dependencies into a container, you can ensure it runs the same way regardless of where it's deployed.
9.3.1 Example: Dockerizing an Express.js Application
# Dockerfile
FROM node:14
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
COPY package*.json ./
RUN npm install
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "app.js" ]