Building robust APIs is a fundamental skill for modern web developers. Node.js and Express provide an excellent foundation for creating scalable, maintainable RESTful APIs. This guide covers everything you need to know.
Setting Up Your Project
Initialize Project
npm init -y
npm install express dotenv cors helmet
npm install -D nodemon
Project Structure
Organize your API with a clear structure:
project/
├── src/
│ ├── controllers/
│ ├── models/
│ ├── routes/
│ ├── middleware/
│ ├── utils/
│ └── app.js
├── .env
└── package.json
Basic Express Setup
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Routes
app.get('/api/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date() });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
RESTful API Design
Follow REST principles:
Example CRUD Operations
// GET all items
app.get('/api/items', async (req, res) => {
try {
const items = await Item.find();
res.json(items);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// POST create item
app.post('/api/items', async (req, res) => {
try {
const item = new Item(req.body);
await item.save();
res.status(201).json(item);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
Middleware
Error Handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: 'Something went wrong!',
message: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});
Authentication
const authenticate = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Verify token
next();
};
Best Practices
1. Input Validation
Use libraries like Joi or express-validator:
const { body, validationResult } = require('express-validator');
app.post('/api/users',
body('email').isEmail(),
body('password').isLength({ min: 8 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process request
}
);
2. Rate Limiting
Prevent abuse with rate limiting:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);
3. Security Headers
Use Helmet.js for security:
const helmet = require('helmet');
app.use(helmet());
4. CORS Configuration
const cors = require('cors');
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
credentials: true
}));
Database Integration
MongoDB with Mongoose
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const ItemSchema = new mongoose.Schema({
name: { type: String, required: true },
description: String,
price: Number
}, { timestamps: true });
const Item = mongoose.model('Item', ItemSchema);
Testing Your API
Use tools like:
Documentation
Document your API with:
Building great APIs requires attention to security, performance, and developer experience. Follow these practices to create APIs that are both powerful and maintainable.