-
캐싱
야 이거 했던 요청을 또해??
동일한 요청이 지속적으로 들어오는 경우에 대해서는 캐싱기능을 사용할 수 있다면 성능이 상승하겠지?
//cache-manager 설치
npm i @nestjs/cache-manager cache-manager
// APP.MODULE 수정
import Joi from 'joi';
import { CacheModule } from '@nestjs/cache-manager';
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthMiddleware } from './auth/auth.middleware';
import { Post } from './post/entities/post.entity';
import { PostModule } from './post/post.module';
import { User } from './user/entities/user.entity';
import { UserModule } from './user/user.module';
const typeOrmModuleOptions = {
useFactory: async (
configService: ConfigService,
): Promise<TypeOrmModuleOptions> => ({
type: 'mysql',
host: configService.get('DB_HOST'),
port: configService.get('DB_PORT'),
username: configService.get('DB_USERNAME'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'),
entities: [Post, User],
synchronize: configService.get('DB_SYNC'),
logging: true,
}),
inject: [ConfigService],
};
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
DB_HOST: Joi.string().required(),
DB_PORT: Joi.number().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_NAME: Joi.string().required(),
DB_SYNC: Joi.boolean().required(),
}),
}),
TypeOrmModule.forRootAsync(typeOrmModuleOptions),
JwtModule.registerAsync({
useFactory: (config: ConfigService) => ({
secret: config.get<string>('JWT_SECRET_KEY'), // .env 파일에 JWT_SECRET_KEY라는 키로 비밀키를 저장해두고 사용합니다.
}),
inject: [ConfigService],
}),
CacheModule.register({
ttl: 60000, // 데이터 캐싱 시간(밀리 초 단위, 1000 = 1초)
max: 100, // 최대 캐싱 개수
isGlobal: true,
}),
PostModule,
UserModule,
],
controllers: [AppController],
providers: [AppService, AuthMiddleware],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(AuthMiddleware) // 미들웨어 적용!
.forRoutes({ path: 'user/check', method: RequestMethod.GET }); // user/check 엔드포인트에만 적용
}
}
POST.SERVICE.TS 수정
import { Cache } from 'cache-manager';
import _ from 'lodash';
import { Repository } from 'typeorm';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import {
BadRequestException, Inject, Injectable, NotFoundException, UnauthorizedException
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CreatePostDto } from './dto/create-post.dto';
import { RemovePostDTO } from './dto/remove-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { Post } from './entities/post.entity';
@Injectable()
export class PostService {
constructor(
@InjectRepository(Post) private postRepository: Repository<Post>,
@Inject(CACHE_MANAGER) private cacheManager: Cache,
) {}
async create(createPostDto: CreatePostDto) {
return (await this.postRepository.save(createPostDto)).id;
}
async findAll() {
const cachedArticles = await this.cacheManager.get('articles');
if (!_.isNil(cachedArticles)) {
return cachedArticles;
}
const articles = await this.postRepository.find({
where: { deletedAt: null },
select: ['id', 'title', 'updatedAt'],
});
await this.cacheManager.set('articles', articles);
return articles;
}
async findOne(id: number) {
if (_.isNaN(id)) {
throw new BadRequestException('게시물 ID가 잘못되었습니다.');
}
return await this.postRepository.findOne({
where: { id, deletedAt: null },
select: ['title', 'content', 'updatedAt'],
});
}
async update(id: number, updatePostDto: UpdatePostDto) {
if (_.isNaN(id)) {
throw new BadRequestException('게시물 ID가 잘못되었습니다.');
}
const { content, password } = updatePostDto;
const post = await this.postRepository.findOne({
select: ['password'],
where: { id },
});
if (_.isNil(post)) {
throw new NotFoundException('게시물을 찾을 수 없습니다.');
}
if (!_.isNil(post.password) && post.password !== password) {
throw new UnauthorizedException('비밀번호가 일치하지 않습니다.');
}
await this.postRepository.update({ id }, { content });
}
async remove(id: number, removePostDto: RemovePostDTO) {
if (_.isNaN(id)) {
throw new BadRequestException('게시물 ID가 잘못되었습니다.');
}
const { password } = removePostDto;
const post = await this.postRepository.findOne({
select: ['password'],
where: { id },
});
if (_.isNil(post)) {
throw new NotFoundException('게시물을 찾을 수 없습니다.');
}
if (!_.isNil(post.password) && post.password !== password) {
throw new UnauthorizedException('비밀번호가 일치하지 않습니다.');
}
await this.postRepository.softDelete({ id });
}
}