Node.js logoNode.jsv4.18INTERMEDIATE

Express.js

Express.js cheat sheet with routing, middleware, request handling, error handling, and REST API patterns with Node.js code examples.

9 min read
expressnodejsbackendapirestmiddleware

Sign in to mark items as known and track your progress.

Sign in

Setup & Basics

Initialize and configure Express applications

Application Setup

Create and configure Express app

javascript
// Install
npm install express

// Basic setup
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000

// Middleware
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(express.static('public'))

// Start server
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

// ES6 modules
import express from 'express'
💡 Use environment variables for configuration
✅ Set up middleware early in the app
⚡ Use compression in production

Routing

Define routes and handle HTTP methods

Route Handling

Define and organize routes

javascript
// Basic routes
app.get('/', (req, res) => {
  res.send('Hello World')
})

app.post('/users', (req, res) => {
  res.json({ user: req.body })
})

// Route parameters
app.get('/users/:id', (req, res) => {
  res.json({ id: req.params.id })
})

// Query parameters
app.get('/search', (req, res) => {
  res.json({ query: req.query.q })
})

// Router
const router = express.Router()
router.get('/', handler)
router.post('/', handler)
app.use('/api', router)

// Route patterns
app.get('/ab?cd', handler)  // abcd, acd
app.get('/ab+cd', handler)  // abcd, abbcd, abbbcd
app.get('/ab*cd', handler)  // abcd, abxcd, abRANDOMcd
app.get(/.*fly$/, handler)  // butterfly, dragonfly
💡 Use routers to organize routes
✅ Order matters - specific routes first
⚡ Use route parameters for dynamic paths

Middleware

Process requests with middleware functions

Middleware Patterns

Create and use middleware

javascript
// Basic middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`)
  next()
})

// Error handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

// Route-specific middleware
app.get('/protected', authenticate, (req, res) => {
  res.json({ data: 'secret' })
})

// Third-party middleware
const cors = require('cors')
const helmet = require('helmet')
const morgan = require('morgan')

app.use(cors())
app.use(helmet())
app.use(morgan('combined'))
💡 Middleware executes in order
✅ Always call next() or send response
⚠️ Error middleware needs 4 parameters

Request & Response

Handle request data and send responses

Request/Response Handling

Work with req and res objects

javascript
// Request properties
req.params    // Route parameters
req.query     // Query string
req.body      // Request body
req.headers   // Headers
req.cookies   // Cookies
req.method    // HTTP method
req.url       // URL path
req.ip        // Client IP

// Response methods
res.send('text')
res.json({ data })
res.status(404).send('Not found')
res.redirect('/login')
res.render('template', { data })
res.sendFile('/path/to/file')
res.download('/path/to/file')

// Headers
res.set('Content-Type', 'application/json')
res.cookie('token', value, { httpOnly: true })
💡 res.json() automatically sets Content-Type
✅ Always set appropriate status codes
⚡ Use streaming for large files

Database Integration

Connect and work with databases

Database Operations

Integrate databases with Express

javascript
// MongoDB with Mongoose
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/myapp')

const User = mongoose.model('User', {
  name: String,
  email: String
})

app.get('/users', async (req, res) => {
  const users = await User.find()
  res.json(users)
})

// PostgreSQL with pg
const { Pool } = require('pg')
const pool = new Pool({
  connectionString: process.env.DATABASE_URL
})

app.get('/users', async (req, res) => {
  const result = await pool.query('SELECT * FROM users')
  res.json(result.rows)
})
💡 Use connection pooling for production
✅ Always handle database errors
⚡ Use indexes for better query performance

Authentication & Security

Secure Express applications

Security Implementation

Authentication and security best practices

javascript
// JWT Authentication
const jwt = require('jsonwebtoken')

app.post('/login', async (req, res) => {
  // Verify credentials
  const token = jwt.sign(
    { userId: user.id },
    process.env.JWT_SECRET,
    { expiresIn: '1d' }
  )
  res.json({ token })
})

// Security middleware
const helmet = require('helmet')
const rateLimit = require('express-rate-limit')

app.use(helmet())
app.use(rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100
}))
🔒 Always hash passwords with bcrypt
✅ Use HTTPS in production
⚠️ Implement rate limiting for all endpoints

Error Handling

Error Handling Middleware

Catch and handle errors gracefully in your Express application

javascript
// Async route handler wrapper
const asyncHandler = fn => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

// Route with async handling
app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await User.findById(req.params.id);
  res.json(user);
}));

// Global error handler (must be last)
app.use((err, req, res, next) => {
  console.error(err.stack);
  
  res.status(err.status || 500).json({
    message: err.message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
});
💡 Error middleware needs 4 parameters (err, req, res, next)
⚠️ Must be defined after all other middleware
✅ Use async wrapper to catch Promise rejections
🔒 Don't expose stack traces in production

CORS & Security

CORS Configuration

Enable Cross-Origin Resource Sharing for API access from browsers

javascript
const cors = require('cors');

// Allow all origins (development)
app.use(cors());

// Specific origin
app.use(cors({
  origin: 'https://example.com'
}));

// Multiple origins
const corsOptions = {
  origin: function (origin, callback) {
    const allowedOrigins = ['https://example.com', 'https://app.example.com'];
    if (allowedOrigins.indexOf(origin) !== -1 || !origin) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true // Allow cookies
};

app.use(cors(corsOptions));
💡 CORS is required for browser-based API calls
⚠️ Don't use wildcard (*) origin in production
🔒 Set credentials: true for cookie support
✅ Configure specific origins for security

Security Headers

Add security headers to protect against common vulnerabilities

javascript
const helmet = require('helmet');

// Use helmet for security headers
app.use(helmet());

// 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
  message: 'Too many requests'
});

app.use('/api/', limiter);

// Prevent MongoDB injection
const mongoSanitize = require('express-mongo-sanitize');
app.use(mongoSanitize());
🔒 Helmet adds various security headers
⚡ Rate limiting prevents abuse
💡 Sanitize inputs to prevent injection
✅ Use HTTPS in production always

Request Validation

Input Validation

Validate and sanitize user input to ensure data integrity

javascript
const { body, param, query, validationResult } = require('express-validator');

// Validation middleware
app.post('/users',
  body('email').isEmail().normalizeEmail(),
  body('name').isLength({ min: 2 }).trim().escape(),
  body('age').isInt({ min: 0, max: 120 }),
  body('password').isLength({ min: 8 }).matches(/\d/),
  (req, res) => {
    // Check validation results
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    
    // Process valid data
    const { email, name, age, password } = req.body;
    // Create user...
  }
);
💡 Always validate user input
✅ Sanitize data to prevent XSS
⚠️ Return clear validation error messages
🔒 Never trust client-side validation alone

Configuration

Environment Variables

Manage configuration and secrets using environment variables

javascript
// Load environment variables
require('dotenv').config();

// Access variables
const PORT = process.env.PORT || 3000;
const DB_URL = process.env.DATABASE_URL;
const JWT_SECRET = process.env.JWT_SECRET;

// Check required variables
const requiredEnvVars = ['DATABASE_URL', 'JWT_SECRET'];
requiredEnvVars.forEach(varName => {
  if (!process.env[varName]) {
    console.error(`Missing required environment variable: ${varName}`);
    process.exit(1);
  }
});

// Start server
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
  console.log(`Environment: ${process.env.NODE_ENV}`);
});
💡 Never commit .env files to version control
🔒 Use different secrets for each environment
✅ Validate environment variables on startup
⚡ Use dotenv for local development