Express Framework Basics
Express is the most popular NodeJS web framework. It simplifies building web servers and APIs by providing a clean, minimal interface on top of the raw http module.
Why Express?
Express makes web development easier:
| Task | Raw HTTP | Express |
|---|---|---|
| Routing | Manual if/else | app.get('/path', ...) |
| JSON parsing | Manual chunks | Built-in |
| Static files | Manual fs.readFile | express.static() |
| Middleware | Manual | Built-in system |
| Error handling | Manual try/catch | Centralized |
Installing Express
# Create new project
mkdir my-app
cd my-app
npm init -y
# Install Express
npm install express
Your First Express Server
// server.js
const express = require('express');
const app = express();
// Define a route
app.get('/', (req, res) => {
res.send('Hello from Express!');
});
// Start server
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Run it:
node server.js
That’s it! Much simpler than raw HTTP.
Routes
Define routes for different HTTP methods:
const express = require('express');
const app = express();
// GET request
app.get('/', (req, res) => {
res.send('<h1>Home Page</h1>');
});
app.get('/about', (req, res) => {
res.send('<h1>About Page</h1>');
});
// POST request
app.post('/api/users', (req, res) => {
res.send('User created');
});
// PUT request
app.put('/api/users/:id', (req, res) => {
res.send(`Updated user ${req.params.id}`);
});
// DELETE request
app.delete('/api/users/:id', (req, res) => {
res.send(`Deleted user ${req.params.id}`);
});
app.listen(3000);
Sending Responses
Express provides multiple ways to send responses:
app.get('/text', (req, res) => {
res.send('Plain text response');
});
app.get('/html', (req, res) => {
res.send('<h1>HTML response</h1>');
});
app.get('/json', (req, res) => {
res.json({ message: 'JSON response', status: 'ok' });
});
app.get('/status', (req, res) => {
res.status(201).json({ created: true });
});
app.get('/redirect', (req, res) => {
res.redirect('/about');
});
app.get('/download', (req, res) => {
res.download('./files/report.pdf');
});
app.get('/file', (req, res) => {
res.sendFile('/absolute/path/to/file.html');
});
Route Parameters
Capture dynamic values from URLs:
// URL parameter
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ userId });
});
// GET /users/123 → { userId: '123' }
// Multiple parameters
app.get('/posts/:year/:month/:slug', (req, res) => {
const { year, month, slug } = req.params;
res.json({ year, month, slug });
});
// GET /posts/2024/01/hello-world
// Optional parameter
app.get('/products/:category/:subcategory?', (req, res) => {
res.json(req.params);
});
// GET /products/electronics → { category: 'electronics' }
// GET /products/electronics/phones → { category: 'electronics', subcategory: 'phones' }
Query Parameters
Access query strings from URLs:
app.get('/search', (req, res) => {
const { q, page, limit } = req.query;
res.json({
searchTerm: q,
page: page || 1,
limit: limit || 10
});
});
// GET /search?q=nodejs&page=2&limit=20
Middleware
Middleware functions execute between receiving a request and sending a response:
const express = require('express');
const app = express();
// Built-in middleware - parse JSON
app.use(express.json());
// Built-in middleware - parse URL-encoded data
app.use(express.urlencoded({ extended: true }));
// Custom middleware - logger
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // Pass to next middleware
});
// Custom middleware - add timestamp
app.use((req, res, next) => {
req.timestamp = new Date();
next();
});
// Route using middleware data
app.get('/', (req, res) => {
res.json({
message: 'Hello',
timestamp: req.timestamp
});
});
app.listen(3000);
Middleware flow:
Request → Middleware 1 → Middleware 2 → Route Handler → Response
Static Files
Serve CSS, images, JavaScript files:
const express = require('express');
const app = express();
// Serve files from 'public' directory
app.use(express.static('public'));
app.listen(3000);
Project structure:
project/
├── server.js
└── public/
├── index.html
├── style.css
├── app.js
└── images/
└── logo.png
Access files:
http://localhost:3000/index.htmlhttp://localhost:3000/style.csshttp://localhost:3000/images/logo.png
Custom path:
// Serve files from 'public' at '/static' route
app.use('/static', express.static('public'));
// Now: http://localhost:3000/static/style.css
Complete API Example
const express = require('express');
const app = express();
// Middleware
app.use(express.json());
// In-memory data store
let users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
let nextId = 3;
// GET /api/users - List all users
app.get('/api/users', (req, res) => {
res.json(users);
});
// GET /api/users/:id - Get single user
app.get('/api/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const user = users.find(u => u.id === id);
if (user) {
res.json(user);
} else {
res.status(404).json({ error: 'User not found' });
}
});
// POST /api/users - Create user
app.post('/api/users', (req, res) => {
const newUser = {
id: nextId++,
name: req.body.name,
email: req.body.email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT /api/users/:id - Update user
app.put('/api/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = users.findIndex(u => u.id === id);
if (index !== -1) {
users[index] = { ...users[index], ...req.body };
res.json(users[index]);
} else {
res.status(404).json({ error: 'User not found' });
}
});
// DELETE /api/users/:id - Delete user
app.delete('/api/users/:id', (req, res) => {
const id = parseInt(req.params.id);
const index = users.findIndex(u => u.id === id);
if (index !== -1) {
const deleted = users.splice(index, 1);
res.json({ message: 'User deleted', user: deleted[0] });
} else {
res.status(404).json({ error: 'User not found' });
}
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Endpoint not found' });
});
// Error handler
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
app.listen(3000, () => {
console.log('API server running on http://localhost:3000');
});
Test with curl:
# Get all users
curl http://localhost:3000/api/users
# Create user
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'
# Update user
curl -X PUT http://localhost:3000/api/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Alice Updated"}'
# Delete user
curl -X DELETE http://localhost:3000/api/users/2
Request Object (req)
Useful properties and methods:
app.get('/info', (req, res) => {
console.log('URL:', req.url); // '/info?name=John'
console.log('Path:', req.path); // '/info'
console.log('Method:', req.method); // 'GET'
console.log('Headers:', req.headers); // { ... }
console.log('Params:', req.params); // URL parameters
console.log('Query:', req.query); // Query string
console.log('Body:', req.body); // POST data (needs middleware)
console.log('IP:', req.ip); // Client IP
console.log('Protocol:', req.protocol); // 'http' or 'https'
console.log('Hostname:', req.hostname); // 'localhost'
res.send('Check console for request details');
});
Response Object (res)
Common methods:
// Send different types
res.send('text or HTML');
res.json({ key: 'value' });
res.sendFile('/path/to/file');
res.download('/path/to/file');
res.redirect('/other-page');
// Set status code
res.status(404).send('Not found');
res.status(201).json({ created: true });
// Set headers
res.set('Content-Type', 'text/html');
res.set({
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
});
// Cookies
res.cookie('name', 'value', { maxAge: 900000 });
res.clearCookie('name');
// End response without data
res.end();
Development Tools
Auto-restart with Nodemon
# Install nodemon
npm install -D nodemon
# Add to package.json scripts
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
}
# Run in dev mode
npm run dev
Now the server restarts automatically when you save files!
Environment Variables
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({
environment: process.env.NODE_ENV || 'development'
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Run with environment variable:
PORT=8080 node server.js
NODE_ENV=production node server.js
Best Practices
✅ DO:
- Use middleware for common tasks
- Handle errors properly
- Use environment variables for config
- Use nodemon in development
- Return appropriate status codes
- Validate input data
❌ DON’T:
- Forget error handlers
- Store sensitive data in code
- Use synchronous operations
- Expose internal errors to users
- Forget to parse request body
Summary
| Feature | Example |
|---|---|
| Create app | const app = express() |
| GET route | app.get('/path', (req, res) => {}) |
| POST route | app.post('/path', (req, res) => {}) |
| Send JSON | res.json({ data }) |
| Send status | res.status(404).send('Not found') |
| URL params | req.params.id |
| Query params | req.query.search |
| Request body | req.body (needs middleware) |
| Middleware | app.use(express.json()) |
| Static files | app.use(express.static('public')) |
| Start server | app.listen(3000) |
Next Article: Routing and Middleware