Redis with Node.js
16. Redis with Node.js
Section titled “16. Redis with Node.js”Architecture: Express + Redis + Database
Section titled “Architecture: Express + Redis + Database”flowchart TB Client[Client / Browser] --> Express[Express.js Server]
Express --> CacheMiddleware{Check Redis Cache<br/>cacheMiddleware} CacheMiddleware -->|Cache HIT ✅| Response[Return cached dataInstant response!] CacheMiddleware -->|Cache MISS ❌| RouteHandler[Route HandlerFetch from DB]
RouteHandler --> DB[Database<br/>MySQL / PostgreSQL] DB --> StoreInRedis[Store in Redis<br/>SETEX with TTL] StoreInRedis --> Response
Express --> RateLimit{Check Rate Limit<br/>INCR key + EXPIRE} RateLimit -->|Under limit ✅| Allow[Allow request] RateLimit -->|Over limit ❌| Block[429 Too Many Requests]
Express --> Session[Session Managementconnect-redis store]
subgraph RedisOps[Redis Operations] RO1[SET / GET / DELBasic CRUD] RO2[HSET / HGETALLHash operations] RO3[RPUSH / LPOPList queue] RO4[INCR / DECRAtomic counters] end
Express --> RedisOps
style Client fill:#3b82f6,color:#fff style Express fill:#7c3aed,color:#fff style CacheMiddleware fill:#f59e0b,color:#fff style Response fill:#059669,color:#fff style RouteHandler fill:#3b82f6,color:#fff style DB fill:#3b82f6,color:#fff style StoreInRedis fill:#7c3aed,color:#fff style RateLimit fill:#ec4899,color:#fff style Allow fill:#059669,color:#fff style Block fill:#ef4444,color:#fff style RedisOps fill:#10b981,color:#fffFlow: Express app uses Redis for: 1) caching (cache-aside middleware), 2) rate limiting (INCR + TTL), 3) session storage (connect-redis), and 4) basic data operations.
Installation
Section titled “Installation”# Initialize a new Node.js projectmkdir redis-demo && cd redis-demonpm init -y
# Install Redis client (ioredis — most popular)npm install ioredis
# Install Express for API examplesnpm install expressConnecting to Redis
Section titled “Connecting to Redis”const Redis = require('ioredis');
const redis = new Redis({ host: '127.0.0.1', port: 6379, // password: 'your_password', // if auth is enabled // db: 0, // database index (0-15)});
redis.on('connect', () => console.log('✅ Redis connected'));redis.on('error', (err) => console.error('❌ Redis error:', err));
module.exports = redis;Basic CRUD Operations
Section titled “Basic CRUD Operations”const redis = require('./redis');
async function examples() { // SET await redis.set('username', 'prathamesh');
// SET with TTL (seconds) await redis.setex('session:xyz', 3600, 'user:42');
// GET const name = await redis.get('username'); console.log(name); // "prathamesh"
// DELETE await redis.del('username');
// INCR await redis.set('visits', 0); await redis.incr('visits');
// Hash operations await redis.hset('user:42', 'name', 'Prathamesh', 'city', 'Pune'); const user = await redis.hgetall('user:42'); console.log(user); // { name: 'Prathamesh', city: 'Pune' }
// List operations await redis.rpush('tasks', 'task1', 'task2', 'task3'); const task = await redis.lpop('tasks'); console.log(task); // "task1"
// Check TTL const ttl = await redis.ttl('session:xyz'); console.log(ttl); // remaining seconds}
examples();Caching API Responses with Express
Section titled “Caching API Responses with Express”const express = require('express');const redis = require('./redis');const axios = require('axios');
const app = express();const CACHE_TTL = 300; // 5 minutes
// Middleware: Check cache before hitting the APIasync function cacheMiddleware(req, res, next) { const cacheKey = `cache:${req.originalUrl}`;
try { const cached = await redis.get(cacheKey); if (cached) { console.log(`✅ Cache HIT: ${cacheKey}`); return res.json({ source: 'cache', data: JSON.parse(cached) }); }
// Store cache key on request for use in route req.cacheKey = cacheKey; next(); } catch (err) { // If Redis fails, don't break the app — proceed to route console.error('Redis error, skipping cache:', err.message); next(); }}
// Route: Fetch products with cachingapp.get('/api/products', cacheMiddleware, async (req, res) => { try { // Simulate a slow database call const products = await fetchProductsFromDB();
// Store in Redis cache if (req.cacheKey) { await redis.setex(req.cacheKey, CACHE_TTL, JSON.stringify(products)); console.log(`📦 Cache SET: ${req.cacheKey}`); }
res.json({ source: 'database', data: products }); } catch (err) { res.status(500).json({ error: err.message }); }});
// Route: Get user profile with Hashapp.get('/api/user/:id', async (req, res) => { const userId = req.params.id; const cacheKey = `user:${userId}`;
// Try Redis first const cached = await redis.hgetall(cacheKey); if (cached && Object.keys(cached).length > 0) { return res.json({ source: 'cache', user: cached }); }
// Fallback to DB const user = await fetchUserFromDB(userId); await redis.hset(cacheKey, user); await redis.expire(cacheKey, 600);
res.json({ source: 'database', user });});
// Route: Rate limitingapp.get('/api/limited', async (req, res) => { const ip = req.ip; const key = `ratelimit:${ip}`;
const current = await redis.incr(key); if (current === 1) { await redis.expire(key, 60); // Reset every minute }
if (current > 10) { return res.status(429).json({ error: 'Too many requests. Try again in a minute.' }); }
res.json({ message: 'Request successful', count: current });});
async function fetchProductsFromDB() { // Simulate DB delay await new Promise(resolve => setTimeout(resolve, 500)); return [{ id: 1, name: 'Laptop' }, { id: 2, name: 'Mouse' }];}
async function fetchUserFromDB(id) { return { id, name: 'Prathamesh', city: 'Pune', role: 'engineer' };}
app.listen(3000, () => console.log('🚀 Server running on port 3000'));Session Management with Express
Section titled “Session Management with Express”const session = require('express-session');const RedisStore = require('connect-redis').default;const redis = require('./redis');
app.use(session({ store: new RedisStore({ client: redis }), secret: 'your-secret-key', resave: false, saveUninitialized: false, cookie: { secure: false, // true in production with HTTPS maxAge: 1000 * 60 * 60 * 24 // 24 hours }}));
app.post('/login', (req, res) => { req.session.userId = 42; req.session.role = 'admin'; res.json({ message: 'Logged in' });});
app.get('/profile', (req, res) => { if (!req.session.userId) { return res.status(401).json({ error: 'Not authenticated' }); } res.json({ userId: req.session.userId });});