Guide to using Redis with NestJS

Introduction

Redis is an in-memory data structure store, used as a database, cache, and message broker. Redis provides very fast access speeds due to storing data in RAM, helping optimize performance for applications requiring low latency and high concurrent query handling capability.

Valkey is an open-source project created to continue the development of Redis after Redis changed its license towards a commercial one. Valkey is fully compatible with existing Redis protocols and libraries, bringing advantages in stability, being completely free (BSD-licensed), and supported by a large community and leading technology corporations.

Detail

First, create a docker-compose.yml file with the following content

services:
valkey:
image: valkey/valkey:8.0-alpine
container_name: valkey
ports:
- "6379:6379"
command: valkey-server --save 60 1 --loglevel warning

The above code uses Docker Compose to initialize a container running Valkey, exposing port 6379 for connection and configuring automatic data saving (snapshotting) every 60 seconds if there is at least 1 change.


Start docker as follows

docker compose up -d


Check that Valkey has started successfully

$ docker exec -it valkey valkey-cli info server
# Server
redis_version:7.2.4
server_name:valkey
valkey_version:8.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:83545c228632fd34
server_mode:standalone
os:Linux 5.15.167.4-microsoft-standard-WSL2 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
gcc_version:15.2.0
process_id:1
process_supervised:no
run_id:7ef43eb17a01df6f2774c7b8c626c5eaae66dfda
tcp_port:6379
server_time_usec:1773892853633397
uptime_in_seconds:127
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:12285173
executable:/data/valkey-server
config_file:
io_threads_active:0
availability_zone:
listener0:name=tcp,bind=*,bind=-::*,port=6379


Next, in the NestJS project, create a valkey.module.ts file to define connection information to valkey; because using valkey is completely compatible with redis, we can directly use ioredis as follows

import {Module, Global} from '@nestjs/common'
import Redis from 'ioredis'

@Global()
@Module({
providers: [
{
provide: 'VALKEY_CLIENT',
useFactory: () => {
return new Redis({
host: 'localhost',
port: 6379,
})
},
},
],
exports: ['VALKEY_CLIENT'],
})
export class ValkeyModule {}


Create a valkey.service.ts file with the following content

import {Injectable, Inject} from '@nestjs/common'
import {Redis} from 'ioredis'

@Injectable()
export class ValkeyService {
constructor(@Inject('VALKEY_CLIENT') private readonly valkey: Redis) {}

async test(key: string, value: any) {
await this.valkey.set(key, value, 'EX', 3600)
const setValue = await this.valkey.get(key)

const hsetKey = key + '-hset'
await this.valkey.hset(hsetKey, 'firstname', 'firstname value')
await this.valkey.hset(hsetKey, 'lastname', 'lastname value')
const hSetValue = await this.valkey.hgetall(hsetKey)

const lpushKey = key + '-lpush'
await this.valkey.lpush(lpushKey, value + 1)
await this.valkey.rpush(lpushKey, value + 2)
await this.valkey.ltrim(lpushKey, 0, 4)
const lpopValue = await this.valkey.lpop(lpushKey)
const rpopValue = await this.valkey.rpop(lpushKey)
const listValue = await this.valkey.lrange(lpushKey, 0, -1)

const saddKey = key + '-sadd'
this.valkey.sadd(saddKey, value)
this.valkey.sadd(saddKey, value)
const smembersValue = await this.valkey.smembers(saddKey)

return {setValue, hSetValue, lpopValue, rpopValue, listValue, smembersValue}
}
}

This code defines basic operations with Valkey/Redis such as:

  • simple key-value storage (SET/GET)
  • working with Hash (HSET/HGETALL)
  • handling non-duplicate sets (SADD/SMEMBERS)
  • managing lists (LPUSH/RPOP/LTRIM)
    • lrange key 0 -1: Get all
    • lpop key: Get the latest element (left) and delete that element
    • rpop key: Get the oldest element (right) and delete that element
  • lindex key 0: Get 1 element at position 0, keeping the data intact


Create a valkey.controller.ts file to use the above service

import {Controller, Get, Query} from '@nestjs/common'
import {ValkeyService} from 'src/service/valkey.service'

@Controller('valkey')
export class ValkeyController {
constructor(private readonly valkeyService: ValkeyService) {}

@Get('test')
async test(@Query() query: {key: string; value: string}) {
return this.valkeyService.test(query.key, query.value)
}
}


Update the app.module.ts file to import valkey

import {Module} from '@nestjs/common'
import {ValkeyService} from './service/valkey.service'
import {ValkeyModule} from './module/valkey.module'
import {ValkeyController} from './controller/valkey.controller'

@Module({
imports: [ValkeyModule],
controllers: [ValkeyController],
providers: [ValkeyService],
})
export class AppModule {}


The result when checked with Postman is as follows

Happy coding!

See more articles here.

Comments

Popular posts from this blog

All Practice Series

Deploying a NodeJS Server on Google Kubernetes Engine

Kubernetes Deployment for Zero Downtime

Setting up Kubernetes Dashboard with Kind

Using Kafka with Docker and NodeJS

Monitoring with cAdvisor, Prometheus and Grafana on Docker

Practicing with Google Cloud Platform - Google Kubernetes Engine to deploy nginx

Kubernetes Practice Series

NodeJS Practice Series

Sitemap