Express.js
Fast, minimalist web framework for Node.js. Simple and highly extensible, widely used for building RESTful APIs and web application servers.
GitHub Overview
expressjs/express
Fast, unopinionated, minimalist web framework for node.
Topics
Star History
Framework
Express.js
Overview
Express.js is a minimal and flexible web application framework for Node.js that provides a robust set of features for web and mobile applications. It enables rapid and simple development of APIs and web sites.
Details
Express.js is a web application framework for Node.js developed by TJ Holowaychuk in 2010. Designed as a "fast, unopinionated, minimalist web framework for Node.js," it provides a powerful set of features for developing web APIs and web applications. The middleware architecture allows flexible customization of application configuration, offering features like routing, HTTP helpers, template engine integration, static file serving, and error handling. While lightweight, it maintains high extensibility with a rich middleware and plugin ecosystem, and is widely adopted for RESTful API development, microservices, and full-stack web application development. It serves as the foundation for many Node.js frameworks (Koa, Nest.js, Fastify, etc.) and has established itself as the default standard for Node.js web development.
Pros and Cons
Pros
- Lightweight & Fast: High performance with minimal configuration
- Middleware Architecture: Flexible and extensible configuration
- Rich Ecosystem: Thousands of middleware and plugins available
- Low Learning Curve: Simple API that's easy to learn
- High Freedom: Not bound to specific design patterns
- Node.js Native: Leverages Node.js asynchronous features
- Large Community: Rich documentation and support
- Production Proven: Adopted by Netflix, Uber, WhatsApp, and others
Cons
- Lack of Structure: Best practices may not be clear in some cases
- Configuration Complexity: Setup can be complex for large applications
- Security: Security settings are left to developers
- Error Handling: Careful attention needed for asynchronous error handling
- Scaling Challenges: Single-threaded model limitations
- TypeScript Support: TypeScript setup required separately by default
Key Links
- Express.js Official Website
- Express.js Official Documentation
- Express.js GitHub Repository
- Express.js Middleware List
- Express Generator
- Express Community
Code Examples
Hello World
const express = require('express');
const app = express();
const port = 3000;
// Basic route
app.get('/', (req, res) => {
res.send('Hello, Express!');
});
// JSON response
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello, World!', timestamp: new Date() });
});
// Start server
app.listen(port, () => {
console.log(`Express server running on port ${port}`);
});
// ES6 module syntax
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello from ES6 Express!');
});
export default app;
Routing and HTTP Methods
const express = require('express');
const app = express();
// JSON parser setup
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// GET route
app.get('/users', (req, res) => {
res.json([
{ id: 1, name: 'John Doe', email: '[email protected]' },
{ id: 2, name: 'Jane Smith', email: '[email protected]' }
]);
});
// Route with parameters
app.get('/users/:id', (req, res) => {
const userId = parseInt(req.params.id);
res.json({ id: userId, name: `User ${userId}`, email: `user${userId}@example.com` });
});
// POST route
app.post('/users', (req, res) => {
const { name, email } = req.body;
const newUser = {
id: Date.now(),
name,
email,
createdAt: new Date()
};
res.status(201).json(newUser);
});
// PUT route
app.put('/users/:id', (req, res) => {
const userId = req.params.id;
const updateData = req.body;
res.json({ id: userId, ...updateData, updatedAt: new Date() });
});
// DELETE route
app.delete('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ message: `User ${userId} deleted successfully` });
});
// Query parameter handling
app.get('/search', (req, res) => {
const { q, page = 1, limit = 10 } = req.query;
res.json({
query: q,
page: parseInt(page),
limit: parseInt(limit),
results: [`${q} result 1`, `${q} result 2`]
});
});
Middleware Usage
const express = require('express');
const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');
const app = express();
// Security middleware
app.use(helmet());
// CORS configuration
app.use(cors({
origin: ['http://localhost:3000', 'https://example.com'],
credentials: true
}));
// Logging middleware
app.use(morgan('combined'));
// Body parser
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Static file serving
app.use('/static', express.static('public'));
// Custom middleware (authentication)
const authenticate = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Authentication token required' });
}
// Token verification logic
req.user = { id: 1, name: 'Test User' };
next();
};
// Rate limiting middleware
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // maximum 100 requests
});
app.use('/api/', limiter);
// Protected route
app.get('/api/profile', authenticate, (req, res) => {
res.json({ user: req.user, message: 'Authenticated user profile' });
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Server error occurred' });
});
Database Integration (MongoDB)
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// MongoDB connection
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// User schema definition
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
createdAt: { type: Date, default: Date.now }
});
const User = mongoose.model('User', userSchema);
app.use(express.json());
// Get users list
app.get('/api/users', async (req, res) => {
try {
const { page = 1, limit = 10 } = req.query;
const users = await User.find()
.select('-password')
.limit(limit * 1)
.skip((page - 1) * limit)
.sort({ createdAt: -1 });
const total = await User.countDocuments();
res.json({
users,
totalPages: Math.ceil(total / limit),
currentPage: page
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Create user
app.post('/api/users', async (req, res) => {
try {
const { name, email, password } = req.body;
// Validation
if (!name || !email || !password) {
return res.status(400).json({ error: 'Required fields are missing' });
}
const user = new User({ name, email, password });
await user.save();
const userResponse = user.toObject();
delete userResponse.password;
res.status(201).json(userResponse);
} catch (error) {
if (error.code === 11000) {
res.status(400).json({ error: 'This email address is already in use' });
} else {
res.status(500).json({ error: error.message });
}
}
});
// Update user
app.put('/api/users/:id', async (req, res) => {
try {
const { id } = req.params;
const updateData = req.body;
delete updateData.password; // Password updates via separate endpoint
const user = await User.findByIdAndUpdate(
id,
updateData,
{ new: true, runValidators: true }
).select('-password');
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Authentication and Session Management
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const app = express();
app.use(express.json());
// Session configuration
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
store: MongoStore.create({
mongoUrl: 'mongodb://localhost:27017/myapp'
}),
cookie: {
secure: false, // true for HTTPS environments
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
}));
// User registration
app.post('/api/auth/register', async (req, res) => {
try {
const { name, email, password } = req.body;
// Password hashing
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(password, saltRounds);
const user = new User({
name,
email,
password: hashedPassword
});
await user.save();
// JWT token generation
const token = jwt.sign(
{ userId: user._id, email: user.email },
'jwt-secret-key',
{ expiresIn: '7d' }
);
res.status(201).json({
message: 'User registration completed',
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Login
app.post('/api/auth/login', async (req, res) => {
try {
const { email, password } = req.body;
// User search
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid email or password' });
}
// Password verification
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
return res.status(401).json({ error: 'Invalid email or password' });
}
// Save to session
req.session.userId = user._id;
// JWT token generation
const token = jwt.sign(
{ userId: user._id, email: user.email },
'jwt-secret-key',
{ expiresIn: '7d' }
);
res.json({
message: 'Login successful',
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// JWT authentication middleware
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, 'jwt-secret-key', (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
// Protected route
app.get('/api/auth/profile', authenticateToken, async (req, res) => {
try {
const user = await User.findById(req.user.userId).select('-password');
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
File Upload Handling
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const app = express();
// Create upload directory
const uploadDir = 'uploads';
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir);
}
// Multer configuration
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
// File filter
const fileFilter = (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Unauthorized file format'), false);
}
};
const upload = multer({
storage,
fileFilter,
limits: {
fileSize: 5 * 1024 * 1024 // 5MB limit
}
});
// Single file upload
app.post('/api/upload/single', upload.single('image'), (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No file selected' });
}
res.json({
message: 'File upload completed',
file: {
filename: req.file.filename,
originalname: req.file.originalname,
mimetype: req.file.mimetype,
size: req.file.size,
path: req.file.path
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Multiple file upload
app.post('/api/upload/multiple', upload.array('images', 5), (req, res) => {
try {
if (!req.files || req.files.length === 0) {
return res.status(400).json({ error: 'No files selected' });
}
const fileInfo = req.files.map(file => ({
filename: file.filename,
originalname: file.originalname,
mimetype: file.mimetype,
size: file.size,
path: file.path
}));
res.json({
message: `${req.files.length} files uploaded successfully`,
files: fileInfo
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// File retrieval
app.get('/api/files/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(uploadDir, filename);
// Check file existence
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'File not found' });
}
res.sendFile(path.resolve(filePath));
});
// File deletion
app.delete('/api/files/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(uploadDir, filename);
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'File not found' });
}
fs.unlink(filePath, (err) => {
if (err) {
return res.status(500).json({ error: 'File deletion failed' });
}
res.json({ message: 'File deleted successfully' });
});
});
// Error handling
app.use((error, req, res, next) => {
if (error instanceof multer.MulterError) {
if (error.code === 'LIMIT_FILE_SIZE') {
return res.status(400).json({ error: 'File size too large' });
}
}
res.status(500).json({ error: error.message });
});