nest

service

PGI 2024. 9. 30. 02:02
반응형

01. 회원가입 서비스

회원가입 로직을 짜보려고 하는데 기존의 노드 방식은 route에서 작업을 한다 라고 하면 nest에서는 레포지토리 서비스 컨트롤러 3개로 나뉘는 느낌이다.

 

레포지토리 : 테이블(db)와 엔티티를 이어주는 중간 다리역할

서비스 : 비즈니스 로직 즉 기존에 node에서 쓰던 route

컨트롤리 : 이모든걸 조종하는 흑막

 

이라고 이해는 했는데 ㅎㅎ 더 찾아 보겠다. 

아래 처럼 1차적으로 짜봣는데 이렇게 Dependency Injection 즉 의존성 주입을 하게 되면 유닛테스트 및 유지보수를 하는데 좋다고 하고 위에 쓴데로 서비스쪽은 비즈니스로직을 db는 레포지토리쪽이 수행을 한다.

 

Repository<Users> < ---- 이부분에서 타입체크도 다시되고ㅎㅎ

 

그리고 중요한거 이 의존성주입은 모듈에서 하기때문에 아래처럼 모듈에 작성을 해줘야 한다.

// service

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import bcrypt from 'bcrypt';
import { Users } from 'src/entities/Users';

@Injectable()
export class UsersService {
  // 레포지토리 : 테이블(db)와 엔티티를 이어준다.
  constructor(
    @InjectRepository(Users)
    private userRepository: Repository<Users>,
  ) {}
  async Join(
    email: string,
    password: string,
    name: string,
    nickname: string,
    phone: number,
  ) {
    const user = await this.userRepository.findOne({ where: { email } });
    if (!email) {
      throw new Error('이메일을 작성해주세요');
    }
    if (!password) {
      throw new Error('비밀번호를 작성해주세요');
    }
    if (!name) {
      throw new Error('이름을 작성해주세요');
    }
    if (!nickname) {
      throw new Error('닉네임을 작성해주세요');
    }
    if (!phone) {
      throw new Error('휴대폰번호를 작성해주세요');
    }
    if (user) {
      throw new Error('이미 존재하는 사용자입니다');
    }
    const hashedPassword = await bcrypt.hash(password, 12);
    await this.userRepository.save({
      email,
      password: hashedPassword,
      name,
      nickname,
      phone,
    });
  }
}

// module

@Module({
  imports: [TypeOrmModule.forFeature([Users])],
  controllers: [UsersController],
  providers: [UsersService],
})

 

02.Exception filters

자 여기서 에러처리를 하는데 문제가 있다 뭐냐면 async안의 에러가 200으로 통과가 된다.
또 에러를 res할수없다.... ㅠㅠ

그레서 아래와 같은 코드를 날려도 res는 안되는 슬픔... 하지만 400에러까지는 됫다.

throw new HttpException('이메일을 작성해주세요', 400);

 

이것을 처리하기 위해 전에 만들엇던 인터셉터를 쓸수도 있지만 exception filter라는 친구를 써보려고 한다.


NestJS에서 제공해주는 예외 처리 방식을 그대로 사용해도 되지만 커스터마이징을 하고 싶은 경우, Exception filter를 사용해 볼 수 있다. NestJS에서는 exception이 발생한 경우, 재사용성을 고려해서 exception에 관한 처리를 한 곳으로 모은 다음 필터링을 거쳐 원하는 형태의 응답으로 반환해주는 방식을 만들어서 사용할 수 있다.

아래는 기본적으로 제공하는 exception filter이다. 

https://docs.nestjs.com/exception-filters


import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

 

커스텀을 해보려고 하는데 아래처럼 하면 개꿀딱
여기서 중요한것은 main에 전체적으로 사용할수 잇도록 문구를 넣어주는것이다.

//httpException.fliter.ts
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
} from '@nestjs/common';
import { Response } from 'express';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const status = exception.getStatus();
    const err = exception.getResponse() as
      | string
      | { error: string; message: string[]; statusCode: 401 };
    console.log(err, status);
    response.status(status).json({ message: err });
  }
}

// main

// 예외처리
  app.useGlobalFilters(new HttpExceptionFilter());

 

03. class-validator

데코레이터를 이용해서 편리하게 오브젝트의 타입을 검증하는 라이브러리 즉 프론트에서 데이터를 잘보냈는지 (타입에 맞춰서) 검증해주는 착한 라이브러리라고 생각하면된다.

npm i class-validator

// 자주쓰는 데코레이터

@IsString() 문자열인지 검증

@IsInt() Int값인지에 대한 검증

@IsBoolean() Boolean값인지에 대한 검증

@IsEmail() 이메일 형식인지에 대한 검증

@IsArray() 배열 값인지에 대한 검증

@IsEnum() Enum값인지에 대한 검증

@IsNumber() 숫자값인지에 대한 검증(소숫점도 검증 가능)

@IsDate() 날짜값인지에 대한 검증

@IsBase64() Base64 값인지에 대한 검증(토큰 처리를 Base64로 했을시 사용)

@IsOptional() 값이 들어오지 않으면 검증을 안해도 된다는 데코레이터

@MaxLength() 최대 길이 제한

@MinLength() 최소 길이 제한

@Length() 길이 제한

@Matches(RegExp('^[가-힣a-zA-Z0-9]*$'), {message : "입력 값을 다시 확인하세요"}) 정규표현식 입력 값을 검증할 떄 사용 

@Min() 최솟값

@Max() 최댓값

 

 

반응형