NestJS Redis를 이용하여 캐시(Cache) 관리

 안녕하세요. 이번에는 Redis을 이용하여 NestJS와 연결을 하고 캐시를 관리해 보도록 하겠습니다.


일단 해당 Local 또는 Remote PC에 Redis가 설치되 있어야 하고 특히 Remote PC는 해당 Redis가 외부에서 통신이 가능하도록 셋팅해야 합니다.


NestJS 공식 문서 링크

Redis 공식 문서 링크


1. npm모듈 설치(dependencies)

- cache-manager(^4.1.0) cache-manager-redis-store(^2.0.0) redis(^4.3.0)를 설치한다

$ npm install cache-manager@^4.1.0 cache-manager-redis-store@^2.0.0 redis@^4.3.0



2. npm모듈 설치(devDependencies)

- @types/cache-manager(^4.0.2) @types/cache-manager-redis-store(^2.0.1)

$ npm install -D @types/cache-manager@^4.0.2 @types/cache-manager-redis-store@^2.0.1


// src/app.module.ts
import * as Joi from '@hapi/joi';
import { CacheModule, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
// cachemanager-redis-store를 사용하여 캐시 관리
import * as redisStore from 'cache-manager-redis-store'; // @^2.0.0
import { RedisClientOptions } from 'redis'; // @^4.5.1
// import type { ClientOpts } from 'redis';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RedisCrudModule } from './redis_crud/redis_crud.module';
// const redisStore = require('cache-manager-redis-store');

@Module({
imports: [
ConfigModule.forRoot({
// env파일 스키마 점검
validationSchema: Joi.object({
REDIS_URL: Joi.string().required(), // env파일에 REDIS_URL가 반드시 있어야함
}),
}),
CacheModule.register<RedisClientOptions>({
store: redisStore,
url: process.env.REDIS_URL,
isGlobal: true, // 모든 모듈에서 사용 가능하도록 설정
}),
RedisCrudModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

코드1) App Module 작성 코드


// src/redis_crudredis_crud.service.ts
import {
CACHE_MANAGER,
HttpException,
Inject,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { Cache } from 'cache-manager';

@Injectable()
export class RedisCrudService {
constructor(
@Inject(CACHE_MANAGER)
private readonly cacheManager: Cache,
) {}

async saveData(key: string, value: string) {
try {
// ttl이 설정되지 않는다면 기본 5초간 유지되고 사라진다. 0은 무제한
const result = await this.cacheManager.set(key, value, { ttl: 0 });
console.log('result : ', result);
return result;
} catch (err) {
throw new HttpException(err.message, err.status ? err.status : 500);
}
}

async getData(key: string) {
try {
const result = await this.cacheManager.get(key);
console.log('result : ', result);
if (!result) {
throw new NotFoundException('데이터가 존재하지 않습니다.');
}
return result;
} catch (err) {
console.log('Error :', err);
throw new HttpException(err.message, err.status ? err.status : 500);
}
}

async deleteData(key: string) {
try {
const result = await this.cacheManager.del(key);
console.log('result : ', result);
if (!result) {
throw new NotFoundException('데이터가 존재하지 않습니다.');
}
return result;
} catch (err) {
console.log('Error :', err);
throw new HttpException(err.message, err.status ? err.status : 500);
}
}
}

코드2) Srevice의 CRD부분 생성


// src/redis_crudredis_crud.controller.ts
import { Controller, Delete, Get, Query } from '@nestjs/common';
import {
ApiOkResponse,
ApiOperation,
ApiQuery,
ApiTags,
} from '@nestjs/swagger';
import { RedisCrudService } from './redis_crud.service';

@ApiTags('Redis CRUD API')
@Controller('redis-crud')
export class RedisCrudController {
constructor(private readonly redisCrudService: RedisCrudService) {}

@Get()
@ApiOperation({
summary: 'Redis Set',
description: 'redis에 key와 value를 각각 string 으로 저장한다',
})
@ApiQuery({
name: 'key',
type: String,
example: 'key',
description: 'redis에 저장될 key값을 지정한다',
})
@ApiQuery({
name: 'value',
type: String,
example: 'value',
description: 'redis에서 지정된 key에 value를 저장한다',
})
@ApiOkResponse({
status: 200,
description: 'redis에 저장 완료후 응답',
schema: {
type: `{
data : boolean;
message : string;
}`,
example: {
data: true,
message: '저장완료',
},
},
})
async create(@Query('key') key: string, @Query('value') value: string) {
console.log('redis create working : ', key, ' / ', value);
return (await this.redisCrudService.saveData(key, value)) === 'OK'
? { data: true, message: '저장완료' }
: { data: false, message: '저장되지 않음' };
}

@Get('get/keys')
@ApiOperation({
summary: 'Redis get',
description: 'redis에서 key를 조회해서 value를 출력한다.',
})
@ApiQuery({
name: 'key',
type: String,
example: 'key',
description: 'redis에 조회될 key값을 지정한다',
})
@ApiOkResponse({
status: 200,
description: 'redis에 조회 완료후 응답',
schema: {
type: `{
data : string;
message : string;
}`,
example: {
data: 'data string',
message: '저장완료',
},
},
})
async getValue(@Query('key') key: string) {
console.log('redis create working : ', key);
return await this.redisCrudService.getData(key);
}

@Delete()
@ApiOperation({
summary: 'Redis Delete',
description: 'redis에 key값을 조회해서 삭제한다',
})
@ApiQuery({
name: 'key',
type: String,
example: 'key',
description: 'redis에서 삭제될 key값을 지정한다',
})
@ApiOkResponse({
status: 200,
description: 'redis에 삭제 완료후 응답',
schema: {
type: `{
data : boolean;
message : string;
}`,
example: {
data: true,
message: '삭제완료',
},
},
})
async delete(@Query('key') key: string) {
console.log('redis create working : ', key, ' / ');
const result = await this.redisCrudService.deleteData(key);
console.log('delete result : ', result);
return { data: true, message: '삭제완료' };
}
}


코드3) Controller부분에서 CRD API 생성

코드1,2,3을 작성하고 Redis을 생성합니다. (cli : redis-server)

사진1) Redis를 Rocal 로 실행


위 동영상1처럼 해당 NestJS와 Redis가 정상적으로 통신하는 것을 알수 있습니다. 해당 Swagger문서는 NestJS을 실행한 다음 url 'http://localhost:3000/api-docs'으로 접속하면 됩니다.


GitHub Repository Link : https://github.com/Alex-Choi0/NestJS_Redis_Cache.git



댓글

이 블로그의 인기 게시물

Lesson 12_1 프로퍼티 노드(Property Node)

DAQ로 전압 측정하기-2

Lesson 12_2 참조를 이용한 프로퍼티노드(Property Node)