새소식

BE/NestJS

NestJS : DTO 패턴 & 회원가입 service

  • -

NestJS 디자인 패턴

Controller

  • express에서 router의 역할
  • request, resposne, domain, url 등을 제어

Service

  • 실제 비즈니스 로직

 

DTO : Data Transfer Object

→ 계층간 데이터 교환을 위한 객체

  • DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용하는 객체
  • Request와 Response용 DTO는 View를 위한 클래스

https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html

 

 


회원가입 Service

cats.request.dto.ts 생성

import { IsEmail, IsNotEmpty, IsString } from 'class-validator';

export class CatRequestDto {
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  password: string;

  @IsString()
  @IsNotEmpty()
  name: string;
}

 

cats.controller.ts 

@Post 

import { CatRequestDto } from './dto/cats.request.dto';

export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  async signUp(@Body() body: CatRequestDto) {
    return "signUp Success"
  }
}

 

email 정보를 빼먹고 Post 요청을 보낼 경우 아래와 같이 Validation에 의해

"email should not be empty"

"email must be an email" 메세지가 출력된다.

 

이제 Service에 데이터를 넘겨주고 서비스에서 로직을 수행하도록 해야한다.

 

cats.controller.ts 

catService 연결

import { CatRequestDto } from './dto/cats.request.dto';

export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  async signUp(@Body() body: CatRequestDto) {
    return this.catsService.signUp(body);
  }
}

 

cats.service.ts

CatsService에 SignUp 서비스를 생성

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import * as bcrypt from 'bcrypt';
import { Cat } from './cats.schema';
import { CatRequestDto } from './dto/cats.request.dto';

@Injectable()
export class CatsService {
  // Dependency Injection
  constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>) {}

  async signUp(body: CatRequestDto) {
    const { email, name, password } = body;
    const isCatExist = await this.catModel.exists({ email });
	
    // 이메일 중복 검사 및 Exception 처리
    if (isCatExist) {
      throw new UnauthorizedException(
        '해당하는 고양이는 이미 존재하는 고양이입니다.',
      );
    }
	
    // 비밀번호 암호화
    const hashedPassword = await bcrypt.hash(password, 10);
	
    // db에 저장
    const cat = await this.catModel.create({
      email,
      name,
      password: hashedPassword,
    });

    return cat
  }
}

 

+ password 암호화 라이브러리 설치 필요

$ npm i bcrypt
$ npm i -D @types/bcrypt

 

cats.module.ts

스키마를 사용하기 위해서 cats.module.ts에 import를 해주어야 한다.

@Module({
  imports: [MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])],
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService],
})

 

cats.schema.ts

 

그러나 현재 return cat을 통해 클라이언트 쪽에 암호화된 비밀번호를 노출시켜서는 안된다.

따라서 스키마 단계에서 비밀번호만 virtual field를 통해 숨긴다. 

@Schema(options)
export class Cat extends Document {
  
  ...
  
  @Prop({
    required: true,
  })
  @IsString()
  @IsNotEmpty()
  password: string;

  readonly readOnlyData: { id: string; email: string; name: string };
}

export const CatSchema = SchemaFactory.createForClass(Cat);

CatSchema.virtual('readOnlyData').get(function (this: Cat) {
  return {
    id: this.id,
    email: this.email,
    name: this.name,
  };
});

 

cats.service.ts

return cat.readOnlyData; 로 반환하게 하면 id, name, email만 반환해주게 된다.

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>) {}

  async signUp(body: CatRequestDto) {
    const { email, name, password } = body;
    
    ...

    return cat.readOnlyData;
  }
}

 


+ Mongoose debug가 터미널에서 출력되게 하는 법

app.module.ts

export class AppModule implements NestModule {
  private readonly isDev: boolean = process.env.MODE === 'dev' ? true : false;

  configure(consumer: MiddlewareConsumer) {
    mongoose.set('debug', this.isDev); // mongoose query log
  }
}

 

 

 

728x90

'BE > NestJS' 카테고리의 다른 글

NestJS : CORS  (0) 2022.06.03
NestJS : swagger  (0) 2022.06.02
NestJS : DB Schema 설계 및 Validation  (0) 2022.05.28
NestJS : MongoDB 연결 및 환경 변수 설정  (0) 2022.05.28
NestJS : 로직  (0) 2022.05.28
Contents