Sling Academy
Home/Node.js/Node + Express + Redis: How to Cache Data

Node + Express + Redis: How to Cache Data

Last updated: January 07, 2024

Introduction

In the bustling world of web development, where speed is king and data is queen, a triumvirate has arisen to ensure your applications run as swiftly as the Mississippi River current. This tutorial embarks you on a journey into the heart of caching using Node.js, Express, and Redis, offering a paddle to navigate through the sometimes murky waters of efficient data handling.

Getting Started

To set the scene, imagine a quaint little server, earnestly delivering data to each and every request. But as the crowd hankers for more, the server’s sweat beading, it craves for some reprieve. Caching, my dear friends, caching is that sweet lemonade on a sultry summer day.

const express = require('express');
const fetch = require('node-fetch');
const redis = require('redis');
const app = express();
const PORT = process.env.PORT || 5000;
const REDIS_PORT = process.env.REDIS_PORT || 6379;
const client = redis.createClient(REDIS_PORT);
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

In the code above, we have laid the foundation of our little application, inviting Express, Redis and Fetch to the soiree.

Basic Caching Strategy

To start off simply, let’s implement a basic caching mechanism for a route that fetches data.

app.get('/data', (req, res) => {
  const fetchData = async () => {
    const response = await fetch('https://api.yourdata-source.com');
    const data = await response.json();
    client.setex('dataKey', 3600, JSON.stringify(data));
    res.send(data);
  };
  client.get('dataKey', (error, data) => {
    if (error) throw error;
    if (data !== null) {
      res.send(JSON.parse(data));
    } else {
      fetchData();
    }
  });
});

Mid-Stream Finesse: Middleware Caching

Once we’re comfortable with the basic cache setup, it’s time to refine our application with middleware, allowing the riverboat of data to flow smoothly past caching checkpoints.

const cache = (req, res, next) => {
  const { id } = req.params;
  client.get(id, (err, data) => {
    if (err) throw err;
    if (data !== null) {
      res.send(JSON.parse(data));
    } else {
      next();
    }
  });
};
app.get('/data/:id', cache, (req, res) => {
  //...handling fetching and responding
});

Advanced Caching Tactics

With a heart as fiery as an entrepreneur struck with inspiration, it’s time to dive into the realm of advanced caching tactics.

// Set data with expiry and dealing with invalidation
client.set('my_data', 'value', 'EX', 10, (err) => {
  if (err) { /* handle error */ }
});

// Hashes for complex data
client.hmset('my_hash', 'field1', 'value1', 'field2', 'value2', (err) => {
  if (err) { /* handle error */ }
});

// Automatically refresh cache after expiration by listening to Redis events
client.on('message', (channel, message) => {
  if (channel === 'expired') {
    // Refresh the cache for the provided message key
  }
});
client.subscribe('__keyevent@0__:expired');

Integrating Data Persistence

As the importance of your data grows as tall as a cottonwood tree, integrating data persistence in your caching strategy comes into play.

// Using Redis' native persistence:
// RDB snapshots or AOF logs configurations
// Ensure in your redis.conf:
save 60 10000
appendonly yes

Conclusion

In this odyssey along the technological river, we’ve outfitted our steamboat with the lore of caching using Node.js, Express, and Redis. Armed with this knowledge, your applications can saunter down the mighty river of user requests with the ease of a calm breeze, delivering data with the grace and speed of an antebellum debutante. Remember, caching is the art of remembering what’s worth remembering; a well-cached application is a sign of any clever programmer’s upbringing and breeding.

Next Article: Node.js + Express: How to return text files

Previous Article: NodeJS: How to use mixins in Pug templates

Series: Node.js & Express Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates