icon

첫 번째 NestJS 애플리케이션 만들기


프로젝트 생성

 NestJS CLI를 사용하여 새 프로젝트를 생성하는 과정은 다음과 같습니다.

  1. NestJS CLI 설치 (이미 설치되어 있지 않은 경우)
npm i -g @nestjs/cli
  1. 새 프로젝트 생성
nest new my-first-nest-project
  1. 프로젝트 설정 선택
  • 패키지 매니저 선택 (npm, yarn, pnpm)
  • 프로젝트 설명 및 저자 정보 입력 (선택사항)
  1. 프로젝트 디렉토리로 이동:
cd my-first-nest-project

프로젝트 구조 분석

 생성된 프로젝트의 기본 구조는 다음과 같습니다.

my-first-nest-project/
├── src/
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── node_modules/
├── package.json
├── tsconfig.json
├── nest-cli.json
└── README.md

주요 파일 설명

  1. main.ts : 애플리케이션의 엔트리 포인트
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
 
async function bootstrap() {
   const app = await NestFactory.create(AppModule);
   await app.listen(3000);
}
bootstrap();
  1. app.module.ts : 루트 모듈 정의
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
 
@Module({
   imports: [],
   controllers: [AppController],
   providers: [AppService],
})
export class AppModule {}
  1. app.controller.ts : 기본 컨트롤러
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
 
@Controller()
export class AppController {
   constructor(private readonly appService: AppService) {}
 
   @Get()
   getHello(): string {
      return this.appService.getHello();
   }
}
  1. app.service.ts : 기본 서비스
import { Injectable } from '@nestjs/common';
 
@Injectable()
export class AppService {
   getHello(): string {
      return 'Hello World!';
   }
}

 이 파일들은 서로 연결되어 작동합니다.

 AppModuleAppControllerAppService를 포함하고, AppControllerAppService를 주입받아 사용합니다.

REST API 엔드포인트 추가

 새로운 엔드포인트를 추가하려면 app.controller.ts를 수정합니다.

import { Controller, Get, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';
 
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}
 
  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
 
  @Post('greet')
  greet(@Body() body: { name: string }): string {
    return `Hello, ${body.name}!`;
  }
}

 여기서 @Post() 데코레이터는 POST 요청을 처리하는 새 엔드포인트를 정의합니다.

 @Body() 데코레이터는 요청 본문을 파싱합니다.

애플리케이션 실행 및 테스트

  1. 애플리케이션 실행
npm run start
  1. 개발 모드로 실행 (실시간 리로딩)
npm run start:dev
  1. 테스트
npm run test
  1. API 테스트 (curl 사용)
curl -X POST http://localhost:3000/greet -H "Content-Type: application/json" -d '{"name":"John"}'

오류 처리

 기본적인 오류 처리는 NestJS에 내장되어 있지만 커스텀 예외 필터를 사용하여 확장할 수 있습니다.

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.ts에 다음 코드를 추가합니다.

app.useGlobalFilters(new HttpExceptionFilter());

새 모듈과 컴포넌트 추가

  1. 새 모듈 생성
nest generate module users
  1. 새 컨트롤러 생성
nest generate controller users
  1. 새 서비스 생성
nest generate service users

 이 명령어들은 src/users/ 디렉토리에 해당 파일들을 생성하고 AppModule에 자동으로 UsersModule을 추가합니다.

주의사항 및 일반적인 실수

  1. 의존성 주입 순환 참조 피하기 : 모듈 간 상호 의존성을 주의깊게 관리해야 합니다.
  2. 비동기 작업 처리 : 프로미스나 옵저버블을 적절히 사용하여 비동기 작업을 처리해야 합니다.
  3. 데코레이터 사용 실수 : 올바른 데코레이터를 올바른 위치에 사용해야 합니다.
  4. 모듈 구조화 : 관련 기능을 적절히 모듈화하여 코드 구조를 체계적으로 유지해야 합니다.
  5. 환경 변수 관리 : 민감한 정보는 환경 변수로 관리하고, 버전 관리 시스템에 포함시키지 않아야 합니다.
  6. 테스트 작성 소홀 : 단위 테스트와 E2E 테스트를 꾸준히 작성하고 유지해야 합니다.
  7. 타입 안전성 무시 : TypeScript의 장점을 최대한 활용하여 타입을 명확히 지정해야 합니다.
  8. 과도한 추상화 : 필요 이상으로 복잡한 구조를 만들지 않도록 주의해야 합니다.

 NestJS로 첫 번째 애플리케이션을 개발할 때는 프레임워크의 기본 구조와 원칙을 이해하는 것이 중요합니다.

 모듈, 컨트롤러, 서비스의 역할을 명확히 구분하고, 의존성 주입 시스템을 효과적으로 활용해야 합니다. 또한, NestJS의 강력한 기능인 데코레이터를 적절히 사용하여 코드의 가독성과 유지보수성을 높일 수 있습니다.

 개발 과정에서 실시간 리로딩을 활용하면 생산성을 크게 향상시킬 수 있습니다.

 npm run start:dev 명령어를 사용하여 코드 변경 시 자동으로 애플리케이션이 재시작되도록 설정하면 개발 속도를 높일 수 있습니다.