NestJS, the progressive Node.js framework, has quickly become a favorite for building efficient, reliable, and scalable server-side applications. One of its strengths is its robustness and extensibility, allowing developers to integrate with various technologies seamlessly. In this article, we’ll explore how to use Redis with NestJS to leverage caching and Pub/Sub functionalities, enhancing the performance and scalability of your applications.
Why Redis?
Redis is an in-memory data structure store widely used as a database, cache, and message broker. Its lightning-fast read and write operations make it an excellent choice for caching and real-time communication.
Some use cases:
- Caching: Reduce database load by storing frequently accessed data.
- Pub/Sub: Enable real-time communication between different parts of your application.
Setting Up Redis
First, ensure you have Redis installed on your machine. If not, follow the instructions from the Redis documentation to get it up and running.
Integrate Redis with Your NestJS Application
To use Redis with NestJS, you’ll need to install the following packages:
npm install --save @nestjs/microservices ioredis @nestjs/bull
npm install --save-dev @types/ioredis
We’re using ioredis
as the Redis client, and @nestjs/microservices
for extending the NestJS architecture to include microservices-like patterns.
Creating a RedisModule
Start by creating a RedisModule to encapsulate all Redis-related functionality.
// redis/redis.module.ts
import { Module } from '@nestjs/common';
import { RedisService } from './redis.service';
@Module({
providers: [RedisService],
exports: [RedisService],
})
export class RedisModule {}
Redis Service for Handling Connections
Next, create a RedisService
which will handle Redis connections and operations for caching and Pub/Sub.
// redis/redis.service.ts
import { Injectable } from '@nestjs/common';
import * as Redis from 'ioredis';
@Injectable()
export class RedisService {
private readonly redisClient: Redis.Redis;
private readonly publisher: Redis.Redis;
private readonly subscriber: Redis.Redis;
constructor() {
this.redisClient = new Redis();
this.publisher = new Redis();
this.subscriber = new Redis();
}
// Caching example: setting a value
async set(key: string, value: string, ttl: number) {
await this.redisClient.set(key, value, 'EX', ttl);
}
// Caching example: getting a value
async get(key: string): Promise<string | null> {
return this.redisClient.get(key);
}
// Pub/Sub example: publishing a message
async publish(channel: string, message: string) {
await this.publisher.publish(channel, message);
}
// Pub/Sub example: subscribing to a channel
subscribe(channel: string, handler: (message: string) => void) {
this.subscriber.subscribe(channel);
this.subscriber.on('message', (chan, message) => {
if (chan === channel) {
handler(message);
}
});
}
}
Using RedisService in a Controller
Let’s create a simple controller demonstrating caching and pub/sub functionality.
// app.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { RedisService } from './redis/redis.service';
@Controller()
export class AppController {
constructor(private readonly redisService: RedisService) {}
@Get('cache-set')
async cacheSet(@Query('key') key: string, @Query('value') value: string) {
await this.redisService.set(key, value, 3600); // Cache for 1 hour
return 'Value cached';
}
@Get('cache-get')
async cacheGet(@Query('key') key: string) {
const value = await this.redisService.get(key);
return value ? `Value: ${value}` : 'Cache miss';
}
@Get('publish')
async publish(@Query('channel') channel: string, @Query('message') message: string) {
await this.redisService.publish(channel, message);
return `Message published to ${channel}`;
}
@Get('subscribe')
async subscribe(@Query('channel') channel: string) {
this.redisService.subscribe(channel, (message) => {
console.log(`Received message from ${channel}: ${message}`);
});
return `Subscribed to ${channel} (Check your server logs for received messages)`;
}
}
Register RedisModule in AppModule
Finally, register the RedisModule in your AppModule to make RedisService accessible throughout your application.
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { RedisModule } from './redis/redis.module';
@Module({
imports: [RedisModule],
controllers: [AppController],
})
export class AppModule {}
Running the Application
To start the application, run:
npm run start
With Redis running, you can now use the provided endpoints to cache data and leverage Pub/Sub for real-time communication.
Example Requests
- Cache a value:
GET http://localhost:3000/cache-set?key=test&value=hello
- Retrieve the cached value:
GET http://localhost:3000/cache-get?key=test
- Publish a message:
GET http://localhost:3000/publish?channel=updates&message=HelloWorld
- Subscribe to a channel (Check server logs for received messages):
GET http://localhost:3000/subscribe?channel=updates
Conclusion
In this article, we’ve explored integrating Redis with NestJS for caching and Pub/Sub functionalities. By leveraging Redis’s powerful capabilities, you can significantly enhance the performance and scalability of your NestJS applications.
Explore further by adding more complex data structures, transactions, and error handling to fit your specific requirements. Happy coding! 🚀