상똥이의 Back-End 공부방

[Nest.js] 프로젝트 초기 설정하는 법 본문

Nest.JS

[Nest.js] 프로젝트 초기 설정하는 법

상똥백 2024. 9. 25. 01:58

 

목차

0. 해야할 것들

1. config service, env

2. cors

3. response object

 


[0. 해야할 것들]

nest의 프로젝트 세팅을 위해 해야할 것들은 아래와 같습니다.

  1. config service & .env
  2. cors 활성화
  3. response object 세팅

(1) Nest.js 공식문서에서 .env파일 내부의 환경변수를 사용할 때에는, ConfigModule의 ConfigService를 사용하도록 추천합니다

 

(2) 프론트엔드와의 api 연결을 위해 cors 활성화가 필요합니다

 

(3) response object 형식을 설정하여 postman 등에서 확인 가능합니다. 특히 오류가 발생했을 때 상태코드와 에러메세지를 출력하도록 설정하면 생산성이 높아집니다

 


[1. configService & env]

루트 경로에 .env 파일을 생성합니다

touch .env

 

config module 사용을 위해 아래의 명령어로 설치해줍니다

npm i --save @nestjs/config

 

app.module.ts의 imports 배열에 아래와 같이 추가해줍니다

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, 			//다른 module에서 import할 필요가 없어짐
      envFilePath: `../.env`,   //.env 파일 경로
    }),
    ...

 

사용 예시는 아래와 같습니다

// .env
PORT=3000
// main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const configService = app.get(ConfigService);
  app.listen(configService.get('PORT'));
}
bootstrap();

 


[2. cors]

main.ts의 bootstrap() 내부에 아래 문구를 추가해줍니다

// main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';

async function bootstrap() {
  ...
  app.enableCors();
  ...
}
bootstrap();

 

또는 아래와 같이 설정할 수도 있습니다

const app = await NestFactory.create(AppModule, { cors: true });

 


[3. response object]

데이터 반환에 성공하는 경우와, 예외가 throw되는 상황에 대해 각각 설정하겠습니다.

 

우선 데이터 반환에 성공하는 경우입니다. 공식문서에 따라 인터셉터로 설정하겠습니다.

src 폴더 아래에 interceptor 폴더를 만들고, 그 안에 response.interceptor.ts 파일을 생성합니다

// src/interceptors/response.interceptor.ts

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

// 응답 객체 형식입니다. 원하는대로 설정하시면 됩니다
export interface TResponse<T> {
  success: boolean;
  result: T | null;
  message: string | null
}

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, TResponse<T>> {
  intercept(context: ExecutionContext, next: CallHandler): Observable<TResponse<T>> {
    return next.handle().pipe(
      map((data) => {
        if (
          data &&
          typeof data === 'object' &&
          'success' in data &&
          'result' in data &&
          'message' in data
        )
          return data; // 반환할 data 형식이 객체인 경우, 객체만 반환하도록 설정했습니다
        return { success: true, data: data, message: null };
        // 객체가 아니면, success와 message도 같이 반환합니다
      }),
    );
  }
}

 

main.ts의 bootstrap() 안에 아래 문구를 추가합니다

// main.ts
    app.useGlobalInterceptors(new TransformInterceptor());

 

반환되는 형식은 아래와 같습니다.

객체형식인 경우

객체가 아닌 경우

 

예외가 throw되는 경우, 공식문서에 따라 exception filter로 구현합니다.

src 폴더 아래에 filters 폴더를 만들고, 그 내부에 http-exception.filter.ts 파일을 생성합니다.

// src/filters/http-exception.filter.ts

import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
import { ErrorHttpStatusCode } from '@nestjs/common/utils/http-error-by-code.util';

// 응답 객체 형식입니다. 원하는 대로 수정하시면 됩니다.
export class TResponse<T> {
  statusCode: ErrorHttpStatusCode;
  message: string;
}
export type TExceptionResponse = string | { message: string; error: string };

type ErrorWithStatus = Error & { getStatus?: () => number };

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: ErrorWithStatus, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const message = this.getMessage(exception);
    const statusCode = this.getStatusCode(exception);

    const errorResponse: TResponse<null> = {
      statusCode: statusCode,
      message,
    };

    return response.status(statusCode).json(errorResponse);
  }

  private getStatusCode(exception: ErrorWithStatus): number {
    if (exception instanceof HttpException) {
      return exception.getStatus();
    }
    return HttpStatus.BAD_REQUEST;
  }

  private getMessage(exception: ErrorWithStatus): string {
    if (exception instanceof HttpException) {
      const exceptionResponse = exception.getResponse() as TExceptionResponse;
      return typeof exceptionResponse === 'string'
        ? exceptionResponse
        : exceptionResponse.message;
    }
    return exception.message;
  }
}

 

main.ts의 bootstrap()내에 아래를 추가합니다

// main.ts

app.useGlobalFilters(new HttpExceptionFilter());

 

반환되는 결과는 아래와 같습니다. 예외 내부에 적은 문구가 함께 출력됩니다