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() 최댓값