Caching: Improving Performance
Implementing caching strategies using Redis or other caching providers to improve application performance.
Implementing Redis Caching in NestJS Services
This document demonstrates how to implement caching within NestJS services using Redis, focusing on caching frequently accessed data or expensive operations. Caching improves application performance by reducing the load on underlying data sources and speeding up response times.
Prerequisites
Before you begin, ensure you have the following installed:
- Node.js (>= 16.x)
- npm or yarn
- Redis server running locally or accessible remotely
Installation
First, create a new NestJS project (if you don't already have one):
nest new nestjs-redis-caching
Next, install the necessary packages:
npm install @nestjs/cache-manager cache-manager redis ioredis --save
or with yarn:
yarn add @nestjs/cache-manager cache-manager redis ioredis
Configuration
Import and configure the CacheModule
in your AppModule
or the module where you plan to use caching. We'll use Redis as the storage provider.
// app.module.ts
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { RedisClientOptions } from 'redis';
import * as redisStore from 'cache-manager-redis-store';
@Module({
imports: [
CacheModule.registerAsync({
useFactory: async () => ({
store: redisStore,
host: 'localhost', // Redis host
port: 6379, // Redis port
ttl: 60, // Time-to-live in seconds (optional)
}),
}),
],
controllers: [],
providers: [],
})
export class AppModule {}
Note: Replace 'localhost'
and 6379
with your Redis server's actual host and port if different. The ttl
option sets the default expiration time for cached items in seconds. Consider using environment variables for host, port, and other configuration values.
Implementing Caching in a Service
Now, let's demonstrate how to use caching within a NestJS service. We'll create a simple service that fetches data from an external API (you can replace this with any expensive operation). First, create a service:
nest generate service example
Then, inject the CacheManager
into your service and use it to cache the API response.
// example.service.ts
import { Injectable, Inject, CACHE_MANAGER } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { HttpService } from '@nestjs/axios'; // You'll need to install @nestjs/axios
import { firstValueFrom } from 'rxjs';
@Injectable()
export class ExampleService {
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private readonly httpService: HttpService,
) {}
async getData(): Promise<any> {
const cachedData = await this.cacheManager.get('example_data');
if (cachedData) {
console.log('Returning data from cache');
return cachedData;
}
console.log('Fetching data from API');
const response = await firstValueFrom(this.httpService.get('https://jsonplaceholder.typicode.com/todos/1')); // Replace with your API endpoint
const data = response.data;
await this.cacheManager.set('example_data', data, { ttl: 30 }); // Cache for 30 seconds
return data;
}
async clearCache(): Promise {
await this.cacheManager.del('example_data');
console.log("Cache cleared");
}
}
@nestjs/axios
and rxjs
: npm install @nestjs/axios rxjs
Explanation:
- We inject the
CACHE_MANAGER
using@Inject
. - The
getData
function first checks if the data exists in the cache usingcacheManager.get('example_data')
. - If the data is found in the cache, it's returned directly.
- If the data is not found, it's fetched from the external API using
@nestjs/axios
. - The fetched data is then stored in the cache using
cacheManager.set('example_data', data, { ttl: 30 })
, with a TTL (time-to-live) of 30 seconds. - An example function
clearCache
is added to demonstrate how to manually invalidate and clear a specific cache entry.
Using the Service in a Controller
Now, let's use the service in a controller to expose an endpoint that retrieves the cached data.
nest generate controller example
Update the controller:
// example.controller.ts
import { Controller, Get, Delete } from '@nestjs/common';
import { ExampleService } from './example.service';
@Controller('example')
export class ExampleController {
constructor(private readonly exampleService: ExampleService) {}
@Get('data')
async getData(): Promise<any> {
return this.exampleService.getData();
}
@Delete('cache')
async clearCache(): Promise {
return this.exampleService.clearCache();
}
}
Testing
Run your NestJS application:
npm run start:dev
Then, access the endpoint in your browser or using a tool like curl:
curl http://localhost:3000/example/data
The first request will fetch data from the API and store it in the cache. Subsequent requests within the TTL will retrieve the data from the cache. Call the delete endpoint to clear the cache:
curl -X DELETE http://localhost:3000/example/cache
Advanced Usage
Custom Cache Keys: Use a custom cache key based on input parameters to cache different results for different inputs.
Cache Invalidation: Implement strategies for invalidating the cache when the underlying data changes.
Error Handling: Add error handling to gracefully handle cache-related errors.
Conclusion
This guide provides a basic example of implementing Redis caching in NestJS services. By caching frequently accessed data or expensive operations, you can significantly improve the performance of your application.