Express Application
Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. Understanding how to create and structure an Express application is fundamental for building backend services.
What is an Express Application?
An Express application is essentially a series of middleware function calls. It's an instance of the express
module that provides methods to:
- Set up middleware
- Define routes
- Configure template engines
- Set up error handling
- Create and start an HTTP server
Creating Your First Express Application
Let's start by creating a basic Express application:
Step 1: Set Up Your Project
First, create a new directory for your project and initialize a Node.js application:
mkdir my-express-app
cd my-express-app
npm init -y
npm install express
Step 2: Create the Main File
Create a file named app.js
(or index.js
) in your project directory:
// 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 World! Welcome to my Express application.');
});
// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Step 3: Run Your Application
Run your application using Node.js:
node app.js
Output:
Server running on port 3000
Now, if you visit http://localhost:3000
in your browser, you'll see the text "Hello World! Welcome to my Express application."
Application Methods
The Express application object provides several methods that are essential for configuring your application:
app.use()
This method is used to mount middleware functions. 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.
// Middleware to log all requests
app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next(); // Don't forget to call next() to pass control to the next middleware
});
// Serving static files
app.use(express.static('public'));
// Parsing JSON request bodies
app.use(express.json());
app.get(), app.post(), app.put(), app.delete(), etc.
These methods define routes for different HTTP methods:
app.get('/users', (req, res) => {
// Handle GET request for /users
res.json([{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]);
});
app.post('/users', (req, res) => {
// Handle POST request for /users
const newUser = req.body;
// Process the new user data...
res.status(201).json({ id: 3, ...newUser });
});
app.set()
This method is used to set various application settings:
// Set the view engine to EJS
app.set('view engine', 'ejs');
// Set views directory
app.set('views', './views');
// Set application variable
app.set('appName', 'My Express App');
Application Configuration
A properly configured Express application should include several key components:
Error Handling
Error handling middleware is defined with four arguments instead of the usual three (err
, req
, res
, next
):
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something went wrong!');
});
Environment Configuration
You should configure your application differently based on the environment:
if (process.env.NODE_ENV === 'development') {
// Development-specific settings
app.use(require('morgan')('dev')); // Logging middleware
} else {
// Production-specific settings
app.set('trust proxy', 1); // Trust first proxy
}
Security Middleware
It's important to add security features to your Express application:
const helmet = require('helmet');
app.use(helmet()); // Adds various HTTP headers for security
const cors = require('cors');
app.use(cors()); // Enable Cross-Origin Resource Sharing
Structuring an Express Application
As your application grows, it's important to structure it properly:
Simple Structure
For small applications, a simple structure might look like this:
my-express-app/
├── node_modules/
├── public/ # Static files
│ ├── css/
│ ├── js/
│ └── images/
├── views/ # Template files
│ └── index.ejs
├── routes/ # Route handlers
│ ├── index.js
│ └── users.js
├── app.js # Main application file
└── package.json
MVC Structure
For larger applications, an MVC (Model-View-Controller) structure is often used:
my-express-app/
├── node_modules/
├── public/
├── app/
│ ├── models/ # Data models
│ ├── views/ # Templates
│ ├── controllers/ # Request handlers
│ └── middleware/ # Custom middleware
├── config/ # Configuration files
├── routes/ # Route definitions
├── app.js
└── package.json
Real-World Example: Building a RESTful API
Let's create a simple RESTful API for managing a list of books:
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Sample data
let books = [
{ id: 1, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 },
{ id: 2, title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
{ id: 3, title: '1984', author: 'George Orwell', year: 1949 }
];
// GET all books
app.get('/api/books', (req, res) => {
res.json(books);
});
// GET a specific book
app.get('/api/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ message: 'Book not found' });
res.json(book);
});
// POST a new book
app.post('/api/books', (req, res) => {
const { title, author, year } = req.body;
if (!title || !author) {
return res.status(400).json({ message: 'Title and author are required' });
}
const newBook = {
id: books.length + 1,
title,
author,
year: year || 'Unknown'
};
books.push(newBook);
res.status(201).json(newBook);
});
// PUT (update) a book
app.put('/api/books/:id', (req, res) => {
const book = books.find(b => b.id === parseInt(req.params.id));
if (!book) return res.status(404).json({ message: 'Book not found' });
const { title, author, year } = req.body;
if (title) book.title = title;
if (author) book.author = author;
if (year) book.year = year;
res.json(book);
});
// DELETE a book
app.delete('/api/books/:id', (req, res) => {
const index = books.findIndex(b => b.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ message: 'Book not found' });
const deletedBook = books[index];
books.splice(index, 1);
res.json(deletedBook);
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
With this API, you can:
- Get all books:
GET /api/books
- Get a specific book:
GET /api/books/1
- Add a new book:
POST /api/books
with a JSON body - Update a book:
PUT /api/books/1
with a JSON body - Delete a book:
DELETE /api/books/1
Best Practices for Express Applications
-
Use environment variables for configuration settings
javascriptconst PORT = process.env.PORT || 3000;
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost/myapp'; -
Handle errors properly
javascriptapp.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send({ error: err.message || 'Server Error' });
}); -
Use async/await for asynchronous operations
javascriptapp.get('/api/data', async (req, res, next) => {
try {
const data = await fetchDataFromDatabase();
res.json(data);
} catch (error) {
next(error); // Pass errors to Express
}
}); -
Use routers to modularize your application
javascript// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
// Handle GET /users
});
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use('/users', usersRouter); -
Add validation for incoming data
javascriptapp.post('/api/users', (req, res) => {
const { name, email, age } = req.body;
if (!name || !email) {
return res.status(400).json({ message: 'Name and email are required' });
}
if (typeof age !== 'undefined' && (isNaN(age) || age < 0)) {
return res.status(400).json({ message: 'Age must be a positive number' });
}
// Process valid data...
});
Summary
Express.js provides a flexible framework for building web applications and APIs in Node.js. By understanding how to create and configure an Express application, you can build robust, scalable server-side applications.
Key points to remember:
- An Express application is created with
express()
and configured with middleware - Routing methods like
app.get()
,app.post()
define how your app responds to client requests - Middleware functions are the building blocks of Express applications
- Proper application structure becomes important as your application grows
- Error handling is critical for maintaining a stable application
Additional Resources
- Express.js Official Documentation
- MDN Web Docs: Express/Node introduction
- Express.js GitHub Repository
Exercises
- Create a basic Express application that serves an HTML page and a CSS file from a public directory.
- Extend the book API example to include validation and persistent storage using a JSON file.
- Create a middleware that logs all requests with their response time.
- Build a simple Express application with multiple routes and error handling.
- Create an Express application that renders dynamic content using a template engine like EJS or Pug.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)