Skip to main content

Express Introduction

What is Express?

Express logo

Express.js (or simply Express) is a minimal and flexible Node.js web application framework that provides a robust set of features for building web applications and APIs. It's known for being unopinionated, meaning it doesn't force you to use any specific tools or libraries, giving developers the freedom to structure their applications as they see fit.

As one of the most popular frameworks for Node.js, Express simplifies the process of building server-side applications by providing a clean interface for handling HTTP requests, setting up middleware, and rendering views.

Why Learn Express?

Before diving into Express, you might wonder why you should learn it:

  • Simplicity: Express provides a thin layer of fundamental web application features without obscuring Node.js features.
  • Flexibility: Express doesn't force opinions or structures on your application.
  • Middleware: The middleware pattern in Express makes it easy to add functionality like authentication, logging, and more.
  • Industry Standard: Many companies use Express for their backend services.
  • Large Ecosystem: Express has a vast ecosystem of plugins and middleware.

Prerequisites

To get the most out of this section, you should have:

  • Basic knowledge of JavaScript
  • Understanding of Node.js fundamentals
  • Familiarity with HTTP methods and status codes (helpful but not required)

Setting Up Your First Express Application

Let's start by creating a simple Express application. First, you'll need to initialize a Node.js project and install Express:

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

Now, let's create a basic server. Create a file called app.js and add the following code:

javascript
// Import the express module
const express = require('express');

// Create an Express application
const app = express();

// Define a route for the home page
app.get('/', (req, res) => {
res.send('Hello, Express!');
});

// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});

To run this application, execute:

bash
node app.js

When you navigate to http://localhost:3000 in your browser, you should see "Hello, Express!" displayed on the page.

Understanding Express Routes

Routes in Express define how an application responds to client requests to specific endpoints. Each route can have one or more handler functions that execute when the route is matched.

Here's an example with multiple routes:

javascript
const express = require('express');
const app = express();

// Home route
app.get('/', (req, res) => {
res.send('Welcome to the Home page');
});

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

// Contact route
app.get('/contact', (req, res) => {
res.send('Contact Us');
});

// 404 - Page Not Found
app.use((req, res) => {
res.status(404).send('Page not found');
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

In this example:

  • When a user visits the root URL (/), they see "Welcome to the Home page"
  • When a user visits /about, they see "About Us"
  • When a user visits /contact, they see "Contact Us"
  • If a user visits any other path, they see "Page not found" with a 404 status code

HTTP Methods in Express

Express supports all the standard HTTP methods. Here's how you can implement them:

javascript
const express = require('express');
const app = express();

// Middleware to parse JSON bodies
app.use(express.json());

// Sample data
let users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];

// GET - Retrieve all users
app.get('/users', (req, res) => {
res.json(users);
});

// POST - Create a new user
app.post('/users', (req, res) => {
const newUser = {
id: users.length + 1,
name: req.body.name
};
users.push(newUser);
res.status(201).json(newUser);
});

// PUT - Update a user
app.put('/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const userIndex = users.findIndex(user => user.id === id);

if (userIndex === -1) {
return res.status(404).json({ message: 'User not found' });
}

users[userIndex].name = req.body.name;
res.json(users[userIndex]);
});

// DELETE - Remove a user
app.delete('/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const userIndex = users.findIndex(user => user.id === id);

if (userIndex === -1) {
return res.status(404).json({ message: 'User not found' });
}

const deletedUser = users[userIndex];
users = users.filter(user => user.id !== id);
res.json(deletedUser);
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

With this code, you've created a simple RESTful API for managing users.

Route Parameters

Route parameters are named segments of the URL that are used to capture values at specific positions in the URL. They're defined by prefixing a colon to the parameter name:

javascript
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`You requested user with ID: ${userId}`);
});

In this example, if you visit /users/42, the response would be "You requested user with ID: 42".

You can define multiple parameters in a single route:

javascript
app.get('/users/:userId/posts/:postId', (req, res) => {
res.send(`User ID: ${req.params.userId}, Post ID: ${req.params.postId}`);
});

Query Strings

Query strings allow you to pass additional information to your routes:

javascript
app.get('/search', (req, res) => {
const query = req.query.q;
const category = req.query.category || 'all';

res.send(`Search for "${query}" in category "${category}"`);
});

If you navigate to /search?q=express&category=framework, the response would be: 'Search for "express" in category "framework"'

Middleware in Express

Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application's request-response cycle. They can:

  1. Execute any code
  2. Make changes to the request and response objects
  3. End the request-response cycle
  4. Call the next middleware in the stack

Here's a simple example of a logging middleware:

javascript
const express = require('express');
const app = express();

// Custom middleware function
const logger = (req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next(); // Call the next middleware
};

// Use the middleware
app.use(logger);

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

app.listen(3000, () => {
console.log('Server running on port 3000');
});

When you access any route, the logger middleware will log the date, HTTP method, and URL to the console.

Built-in Middleware

Express comes with several built-in middleware functions:

javascript
// Parse JSON bodies
app.use(express.json());

// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded({ extended: true }));

// Serve static files from a directory
app.use(express.static('public'));

Real-World Example: A Todo API

Let's put everything together to create a simple todo API:

javascript
const express = require('express');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// Sample data
let todos = [
{ id: 1, text: 'Learn Express', completed: false },
{ id: 2, text: 'Build an API', completed: false }
];

// Get all todos
app.get('/todos', (req, res) => {
res.json(todos);
});

// Get a specific todo
app.get('/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const todo = todos.find(t => t.id === id);

if (!todo) {
return res.status(404).json({ message: 'Todo not found' });
}

res.json(todo);
});

// Create a new todo
app.post('/todos', (req, res) => {
if (!req.body.text) {
return res.status(400).json({ message: 'Text is required' });
}

const newTodo = {
id: todos.length + 1,
text: req.body.text,
completed: false
};

todos.push(newTodo);
res.status(201).json(newTodo);
});

// Update a todo
app.put('/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const todoIndex = todos.findIndex(t => t.id === id);

if (todoIndex === -1) {
return res.status(404).json({ message: 'Todo not found' });
}

const updatedTodo = {
...todos[todoIndex],
...req.body
};

todos[todoIndex] = updatedTodo;
res.json(updatedTodo);
});

// Delete a todo
app.delete('/todos/:id', (req, res) => {
const id = parseInt(req.params.id);
const todoIndex = todos.findIndex(t => t.id === id);

if (todoIndex === -1) {
return res.status(404).json({ message: 'Todo not found' });
}

const deletedTodo = todos[todoIndex];
todos = todos.filter(t => t.id !== id);
res.json(deletedTodo);
});

app.listen(3000, () => {
console.log('Todo API running on port 3000');
});

With this API, you can:

  • Get all todos: GET /todos
  • Get a specific todo: GET /todos/:id
  • Create a new todo: POST /todos
  • Update a todo: PUT /todos/:id
  • Delete a todo: DELETE /todos/:id

Summary

In this introduction to Express.js, we covered:

  • What Express is and why it's useful
  • How to set up a basic Express application
  • Working with routes and different HTTP methods
  • Using route parameters and query strings
  • Understanding middleware and its importance
  • Building a simple RESTful API

Express provides a solid foundation for building web applications and APIs with Node.js. Its simplicity and flexibility make it an excellent choice for beginners and experienced developers alike.

Additional Resources

To deepen your understanding of Express, check out these resources:

Exercises

  1. Create a simple Express server that returns "Hello, World!" on the home route.
  2. Modify your server to include routes for /about and /contact pages.
  3. Create a books API with routes to get all books, get a single book by ID, add a new book, update a book, and delete a book.
  4. Implement a custom middleware that logs all incoming requests to your server.
  5. Build a simple blog application with Express that displays a list of posts and allows viewing individual posts by ID.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)