Skip to main content

Web Servers with Express.js

What is Express.js?

Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. It is designed for building single-page, multi-page, and hybrid web applications.

Think of Express.js as a powerful and lightweight tool that allows you to build robust and scalable web applications quickly and easily. It's like the backbone of your web server, providing the essential structure and tools you need to create server-side applications.

Why Use Express.js?

Express.js is popular because it:

  • Minimal and Flexible: Provides a thin layer of fundamental web application features without obscuring Node.js features.
  • Robust Routing: Offers robust routing capabilities to handle different HTTP requests.
  • Middleware Support: Allows for the use of middleware to handle various tasks such as parsing request bodies, handling cookies, and managing sessions.
  • Easy Integration: Easily integrates with various template engines and databases.
  • High Performance: Optimized for high performance and efficient handling of HTTP requests.

Core Concepts of Express.js

  1. Routing:
    • Definition: Routing refers to how an application’s endpoints (URIs) respond to client requests.
    • Usage: Define various routes for handling different HTTP methods and endpoints.
  2. Middleware:
    • Definition: 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.
    • Usage: Middleware can perform a variety of tasks, such as logging, authentication, data parsing, and more.
  3. Templates:
    • Definition: Templates are used to render dynamic content on the web pages.
    • Usage: Express.js supports various template engines like Pug, EJS, and Handlebars.
  4. Error Handling:
    • Definition: Error handling middleware catches and processes errors that occur during the request-response cycle.
    • Usage: Define custom error handling middleware to manage errors effectively.

Practical Examples

When to Use Express.js:

  1. Single Page Applications (SPA):
    • Scenario: Building a SPA with dynamic user interactions.
    • Why Express.js?
      • Efficient Routing: Easily handle multiple routes and dynamic content.
      • Middleware Support: Integrate middleware for handling sessions, authentication, and more.
  2. RESTful APIs:
    • Scenario: Developing a RESTful API for a web or mobile application.
    • Why Express.js?
      • Flexible: Easily define routes for CRUD operations.
      • Performance: High performance and low overhead for handling API requests.

When Not to Use Express.js:

  1. Static Sites:

    • Scenario: Building a simple static website with no server-side logic.
    • Why Not Express.js?
      • Overhead: Using Express.js adds unnecessary complexity for purely static sites.

    Alternative: Static site generators (e.g., Jekyll, Hugo)

  2. Complex Enterprise Applications:

    • Scenario: Developing a large-scale enterprise application requiring complex features and strict type checking.
    • Why Not Express.js?
      • Limited Features: May not provide the extensive features required for very complex applications.

    Alternative: Full-fledged frameworks (e.g., Spring Boot, Django)

Common Express.js Use Cases

Some common use cases for Express.js include:

  • Single Page Applications (SPA): Efficient routing and middleware support.
  • RESTful APIs: Flexibility in defining routes and handling requests.
  • Prototyping: Quick setup and easy-to-use structure for prototyping new applications.

Getting Started with Express.js

Step 1: Set Up Your Environment

  1. Install Node.js:
  2. Initialize a New Project:
    • Create a new directory and initialize it with npm:

    mkdir my-express-app
    cd my-express-app
    npm init -y

Step 2: Install Express.js

Install Express.js using npm:


npm install express

Step 3: Set Up Basic Express Server

Create an index.js file and set up a basic Express server:

jsCopy code
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Hello World!');
});

app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});

Step 4: Define Routes

Add routes to handle different endpoints:


app.get('/about', (req, res) => {
res.send('About Page');
});

app.post('/contact', (req, res) => {
res.send('Contact Page');
});

Step 5: Use Middleware

Integrate middleware to handle requests:


const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/data', (req, res) => {
res.send(req.body);
});

Step 6: Error Handling

Add error handling middleware:


app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});

Step 7: Serve Static Files

Serve static files such as images, CSS files, and JavaScript files:


app.use(express.static('public'));

Step 8: Use Template Engines

Set up a template engine for rendering dynamic content:


app.set('view engine', 'pug');

app.get('/template', (req, res) => {
res.render('index', { title: 'Hey', message: 'Hello there!' });
});

Step 9: Connect to a Database

Integrate a database like MongoDB using Mongoose:


const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true,
});

const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
console.log('Connected to MongoDB');
});

Step 10: Define a Schema and Model

Create a Mongoose schema and model:


const userSchema = new mongoose.Schema({
name: String,
email: String,
age: Number,
});

const User = mongoose.model('User', userSchema);

Step 11: Implement CRUD Operations

Add CRUD operations to your Express server:


// Create a new user
app.post('/users', async (req, res) => {
const user = new User(req.body);
try {
await user.save();
res.status(201).send(user);
} catch (error) {
res.status(400).send(error);
}
});

// Read all users
app.get('/users', async (req, res) => {
try {
const users = await User.find();
res.send(users);
} catch (error) {
res.status(500).send(error);
}
});

// Read a user by ID
app.get('/users/:id', async (req, res) => {
const _id = req.params.id;
try {
const user = await User.findById(_id);
if (!user) {
return res.status(404).send();
}
res.send(user);
} catch (error) {
res.status(500).send(error);
}
});

// Update a user by ID
app.patch('/users/:id', async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdates = ['name', 'email', 'age'];
const isValidOperation = updates.every((update) =>
allowedUpdates.includes(update)
);

if (!isValidOperation) {
return res.status(400).send({ error: 'Invalid updates!' });
}

try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, {
new: true,
runValidators: true,
});

if (!user) {
return res.status(404).send();
}

res.send(user);
} catch (error) {
res.status(400).send(error);
}
});

// Delete a user by ID
app.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);

if (!user) {
return res.status(404).send();
}

res.send(user);
} catch (error) {
res.status(500).send(error);
}
});

Step 12: Test Your API

Use a tool like Postman or cURL to test your API endpoints. Perform CRUD operations on the /users endpoint to create, read, update, and delete users.

Conclusion

Express.js is a powerful and flexible web application framework for Node.js. Whether you're building single-page applications, RESTful APIs, or prototyping new ideas, Express.js provides the essential tools and structure to get started quickly. This guide gives you a solid foundation to start building web applications with Express.js. As you progress, you'll discover more advanced features and capabilities that Express.js has to offer.