NestJS는 Node.js 위에서 동작하는 백엔드 프레임워크입니다. TypeScript를 기본적으로 지원하며, Module, Controller, Provider와 같은 구성 요소를 이용해 애플리케이션을 구조적으로 개발할 수 있습니다.

이번 주에는 NestJS의 기본 구조를 공부하고, 메모리에 데이터를 저장하는 Restaurant CRUD API를 만들어봅니다.😄

공부할 내용 📚

1. Why NestJS? 🦁

NestJS를 본격적으로 공부하기 전에 NestJS가 등장한 배경과 특징을 가볍게 살펴봅시다.

2. NestJS 기본 구조 📝

NestJS 프로젝트의 구조와 각 구성 요소의 역할을 공부합니다.

  • NestJS 프로젝트 구조와 Module
  • Controller와 Routing
  • Provider와 Service
  • Dependency Injection
  • Decorator

NestJS 공식 문서에서 아래 부분을 읽어보세요.

  • First steps: NestJS 프로젝트의 기본 파일 구조와 실행 방법을 살펴보세요.
  • Modules: Module이 Controller와 Provider를 구성하는 방법을 살펴보세요.
  • Controllers: Controller, Routing, 요청 처리에 사용하는 Decorator를 살펴보세요.
  • Providers: Provider와 Service의 역할, Dependency Injection을 살펴보세요.

온보딩

Codedang의 announcement 컴포넌트를 살펴보며 다음 내용을 확인해 보세요.

  • Module에 Controller와 Service가 등록되는 방법
  • Controller가 요청을 받고 Service를 호출하는 과정
  • 생성자를 통해 Service가 주입되는 방법
  • Controller와 Service의 역할 차이

Guard, Pipe, Prisma 관련 코드는 이후에 학습하므로 이번에는 전체적인 흐름만 가볍게 살펴봅시다!

API Testing Tool 설치

백엔드의 주요 업무가 API를 설계하고 개발하는 일인만큼, 직접 API를 보내고 테스트할 수 있는 API Testing Tool을 설치해 사용해보는 것을 권장드립니다.

다양한 API Testing Tool이 있는데, 저희 스꾸딩에서는 Bruno를 씁니다. 스크린샷 2025-03-30 오후 11 03 26

아래의 링크에서 다운받으시면 돼유~!

https://www.usebruno.com/downloads

아래 프로젝트 실습에서 API 테스트를 Bruno로 진행하시면 됩니다!

프로젝트 실습 🎈

NestJS를 활용하여 율전 근처의 맛집을 관리하는 Restaurant CRUD API를 구현해봅시다. 아직 데이터베이스는 사용하지 않으며, 식당 데이터는 Service의 배열에 저장합니다.

환경 설정 ⚙️

Nest CLI를 사용하여 새로운 프로젝트를 생성합니다.

  • npm i -g @nestjs/cli 로 Nest CLI 설치하기
  • 생성할 프로젝트 이름으로 새로운 nest 프로젝트 생성 ( 예시 : nest new restaurant )
    • cd restaurant로 생성된 프로젝트 폴더로 이동하기
    • nest g mo restaurants(원하는 이름대로!) 으로 모듈 생성하기
    • nest g co restaurants 으로 controller도 추가해주기
    • nest g s restaurants 으로 service도 추가해주기
  • 서버 시작은 pnpm start:dev (파일 변경 사항을 감지하여 자동으로 반영) 혹은 pnpm start를 이용해주시면 됩니다!
    • package.json 에 자세히 있으니 참고해주세요.
  • 다음 주차에서는 이번 주차에 작성한 코드를 바탕으로 DTO, Validation, Pipe, Exception, Guard 등을 추가할 예정입니다.
  • 아직 DTO, Validation, Pipe와 데이터베이스는 사용하지 않습니다.

유의사항

  • 프로젝트를 생성할 때 패키지 매니저는 pnpm을 선택해주세요.
  • Restaurant은 id, name, address, phone을 가집니다.
  • TypeScript의 interface 또는 type을 사용하여 Restaurant 타입을 정의해주세요.
  • 식당 데이터는 RestaurantsService의 배열에 저장해주세요.
  • 기존 restaurants.json의 데이터를 참고하여 초기 데이터를 구성해도 됩니다.
  • Controller는 HTTP 요청을 받고 Service를 호출합니다.
  • Service는 식당 데이터를 조회하거나 변경합니다.
  • Controller에서 식당 데이터를 직접 저장하거나 변경하지 마세요.
  • API는 Bruno를 사용하여 테스트해주세요.

GET /restaurants

전체 맛집 목록을 반환합니다.

{
  "restaurants": [
    {
      "id": 1,
      "name": "봉수육",
      "address": "경기 수원시 장안구 율전로108번길 11 1층",
      "phone": "0507-1460-0903"
    }
  ]
}

GET /restaurants/:id

id에 해당하는 맛집 정보를 반환합니다.

{
  "id": 1,
  "name": "봉수육",
  "address": "경기 수원시 장안구 율전로108번길 11 1층",
  "phone": "0507-1460-0903"
}

POST /restaurants

새로운 맛집을 추가합니다.

Request Body

{
  "name": "맛집 이름",
  "address": "맛집 주소",
  "phone": "전화번호"
}

식당의 id는 서버에서 생성하고, 생성된 맛집 정보를 반환합니다.

{
  "id": 2,
  "name": "맛집 이름",
  "address": "맛집 주소",
  "phone": "전화번호"
}

PATCH /restaurants/:id

id에 해당하는 맛집 정보를 수정합니다. 변경할 값만 Request Body에 담아 전달합니다.

Request Body

{
  "address": "변경된 맛집 주소"
}

수정된 맛집 정보를 반환합니다.

{
  "id": 1,
  "name": "봉수육",
  "address": "변경된 맛집 주소",
  "phone": "0507-1460-0903"
}

수정과 관련된 요청에는 주로 PUTPATCH를 사용합니다. 두 메서드의 차이도 가볍게 살펴보세요.

DELETE /restaurants/:id

id에 해당하는 맛집을 삭제하고, 삭제된 맛집 정보를 반환합니다.

{
  "id": 1,
  "name": "봉수육",
  "address": "경기 수원시 장안구 율전로108번길 11 1층",
  "phone": "0507-1460-0903"
}