E-commerce Application(Nest js Microservice) - 3. Auth-Service(2)

#1 패키지 설치

npm i class-validator class-transformer

해당 패키지들은 유효성을 검사해주는 패키지입니다. 예를 들어 요청받은 email이 string값인지 확인하기 위해서 @IsString이라는 데코레이터를 사용하여 유효성을 판단할 수 있습니다.

#2 vo, dto, entity

nest js에서는 dto로 통일하는 것 같지만 저는 vo와 dto로 따로 나누어 구현하도록 하겠습니다.

  • request.register.ts
import { IsString } from 'class-validator';

export class RequestRegister {
    @IsString()
    @IsNotEmpty()
    readonly email: string;
    
    @IsString()
    @IsNotEmpty()
    readonly password: string;
    
    @IsString()
    @IsNotEmpty()
    readonly nickname: string;
}
  • request.login.ts
import { IsString } from 'class-validator';

export class RequestLogin {
    @IsString()
    @IsNotEmpty()
    readonly email: string;
    
    @IsString()
    @IsNotEmpty()
    readonly password: string;
}
  • request.update.ts
import { IsString } from 'class-validator';

export class RequestUpdate {
    @IsString()
    @IsNotEmpty()
    readonly nickname: string;
}
  • response.user.ts
export class ResponseUser {
    email: string;
    nickname: string;
    encryptedPwd: string;
    userId: string;
}
  • user.dto.ts
import { IsNumber, IsString } from 'class-validator';

export class UserDto {
    @IsNumber()
    id: number;

    @IsString()
    email: string;

    @IsString()
    password: string;
    
    @IsString()
    nickname: string;
    
    @IsString()
    encryptedPwd: string;
    
    @IsString()
    userId: string;
}
  • user.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class UserEntity {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    email: string;
    
    @Column()
    nickname: string;
    
    @Column()
    userId: string;
    
    @Column()
    encryptedPwd: string;
}

해당 클래스들은 요청을 위한 vo객체로 read-only의 특성을 가집니다. 그리고 IsString이라는 데코레이터를 이용해 변수들이 string값인지 판별해줍니다. 하지만 예외로 ResponseUser라는 클래스는 service 레이어에서부터 반환값으로 계속 넘기면서 최종적으로 유저가 응답을 받을 수 있게 하는 클래스이고, 응답을 위해 값을 넣어줘야 하기 때문에 readonly라는 지시자를 넣지 않았습니다.

그리고 dto클래스는 레이어간 데이터를 넘겨주면서 비즈니스 로직을 거쳐 데이터가 수정되어야 할 때 데이터를 수정해야하기 때문에 readonly라는 지시자를 쓰지 않았습니다.

entity클래스는 service레이어에서 repository의 save메서드를 호출하면서 데이터베이스에 저장될 객체입니다.

#2 service

uuid를 이용하여 userId를 만들 것이기 때문에 다음과 같은 패키지들을 설치하겠습니다.

npm i uuid
npm i -D @types/uuid

Controller에서는 요청받은 데이터를 dto클래스로 변환시켜 Service 레이어를 호출하여 관련 비즈니스 로직을 가집니다. 예를 들어 현재 구현을 위한 시나리오를 살펴보겠습니다.

1) Controller에서는 RequestRegister 객체를 전달받고, 이 객체를 이용하여 Service레이어로 보낼 UserDto라는 객체를 만듭니다.

2) Service에서는 이 UserDto를 전달받고 실질적으로 데이터베이스에 저장을 위해서 UserEntity 객체를 만듭니다.

그리고 UserEntity에 UserDto에서 값을 읽어와 데이터베이스에 저장될 값을 넣어줍니다. 이후 ResponseUser라는 객체를 만들어 회원가입이 완료되었을 때, 사용자에게 보여줄 값들을 반환합니다.

코드를 살펴 보겠습니다.

  • UserController.register
@Post('register')
public async register(@Body() requestRegister: RequestRegister): Promise<ResponseUser> {
    const userDto = new UserDto();

    userDto.email = requestRegister.email;
    userDto.password = requestRegister.password;
    userDto.nickname = requestRegister.nickname;

    return await this.userService.register(userDto);
}
  • UserService.register
public async register(userDto: UserDto) : Promise<ResponseUser> {  
    try {
        const user = new UserEntity();

        user.email = userDto.email;
        user.encryptedPwd = userDto.password + "encrypted";
        user.nickname = userDto.nickname;
        user.userId = uuid();

        await this.userRepository.save(user);
            
        const responseUser = new ResponseUser();

        responseUser.email = user.email;
        responseUser.encryptedPwd = user.encryptedPwd;
        responseUser.nickname = user.nickname;
        responseUser.userId = user.userId;

        return responseUser;
    } catch(err) {
        throw new HttpException(err, HttpStatus.BAD_REQUEST);
    }
}

이런 식의 코드로 회원가입이 진행이 됩니다.

#3 user.module.ts, main.ts

repository를 추가함에 따라 user.module.ts에 import해야 될 코드입니다.

  • user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserEntity } from 'src/entity/user.entity';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule {}

class-validator, class-transformer 패키지를 설정하면서 추가해야할 코드입니다.

  • main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      transform: true,
      forbidNonWhitelisted: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
    }),
  );

  await app.listen(7000); // on PORT 7000
}

bootstrap();

#4 register 결과값 확인




총 2개의 회원가입을 진행해보았고 예상에 잘 맞게 데이터가 저장된 모습입니다.

다음 포스트에서는 login과 인증, 인가에 대한 글을 작성해보도록 하겠습니다.

좋은 웹페이지 즐겨찾기