본문 바로가기
BackEnd/nest.js

[Nest.js] Nest.js 특징, 구조, CRUD

by Chaedie 2023. 2. 6.
728x90

Nest.js 는 Node.js Express를 기반으로 한 프레임웤이다. (선택적으로 Fasify를 사용할 수도 있다.)

nest는 Java진영의 Spring Boot를 한번이라도 봤다면 친숙한 느낌을 받을 수 있다. 이는 아키텍쳐 자체가 Sping Boot의 그것과 유사하고 @Annotaion을 통해 링크하는 점이 같기 때문이다.

nest의 아키텍쳐는 Angular에서 영감을 받았다고 하는데... (이 부분은 앵귤러를 사용해보지 않아서 의아한데,,, 아무튼 스프링 사용자들도 앵귤러를 좋아하는 걸 보면 그 두 프레임웤 또한 유사하다고 봐도 될것 같다..?)


장점

nest.js를 공부해보고 있는 입장에서 느낀 nest의 장점은 빠른 시간 내로 간단한 Application이 깔끔하게 만들어 진다는 것이다. Javascript 문법에 익숙하고, Web 개발에 대해 알고 있다면 몇시간 내로 간단한 장난감 앱을 완성시킬수 있는 생산성이 큰 개발 도구라고 생각한다.

특히나 웹개발을 처음 배울 당시 Spring, Node.js-Express을 찍먹하면서 MySQL 때문에 머리가 많이 아팠었는데 TypeORM을 사용하니 정말 간단하게 쿼리문을 짤 수 있어서 편하고 빠르다고 생각했다.

물론 예전엔 웹개발을 시작하는 입장에서 ERD 테이블을 20개를 깔아두니 머리가 아팠던거긴한데... 아무튼.. ㅎㅎ

단점

단점은 아직 잘 모른다.
구글링해보면 node.js 백엔드의 단점으로

1. Single Thread 이기에 하나의 작업이 오래 걸리는 웹 서비스의 경우 성능 저하 우려있음
2. 해당 코드를 수행해야 어디서 에러 났는지 확인 가능하며 에러 날 경우 프로세스 자체가 내려갈 수 있다.
3. 세션을 공유할 경우 redis와 같은 부가적인 인프라가 필요하다.

등이 있다고 하는데, nest에서는 어떻게 해결할지 궁금하다. 위 단점들을 예의 주시하며 공부해보면 좋은 공부가 될것 같다.

장점에서 node.js 백엔드 장점은 언급안했는데, 단점만 적으면 섭섭하니 간략하게 짚고 가겠다.

1. Non-Blocking I/O로 처리되어 서비스 종류에 따라 성능에 장점이 있음
2. 내장 HTTP가 있어 간단하게 웹 서버를 띄울수 있음
3. FE-BE가 모두 Javascript로 개발하게 되어 백프 소통, 코드 리뷰 등에 장점이 있다.

내가 Nest.js를 배우는 이유

프론트엔드 개발자로 일하고 있으며, Javascript의 생산성에 매료된 상태이기에 굳이 다른 언어 (Java/Spring, Python) 등을 따로 배우는 것 보단 Node/Nest 를 배우는게 백엔드 공부하는 데 드는 리소스를 최소화 할것으로 예상했기 때문.

거기다 Express에 비해 깔끔한 아키텍쳐를 처음부터 제공해주기 때문에 좋다고 생각했음.

거기다 node 백엔드를 한다면 nest는 당연한 스택이 된것 같기도 해서.. ? (react 진영의 Next.js 느낌)


0. 구조

📦src  
 ┣ 📂auth  
 ┃ ┣ 📂dto  
 ┃ ┃ ┗ 📜auth-credentials.dto.ts  
 ┃ ┣ 📜auth.controller.ts  
 ┃ ┣ 📜auth.module.ts  
 ┃ ┣ 📜auth.service.ts  
 ┃ ┗ 📜user.entity.ts  
 ┣ 📂tasks  
 ┃ ┣ 📂dto  
 ┃ ┃ ┣ 📜create-task.dto.ts  
 ┃ ┃ ┣ 📜get-tasks-filter.dto.ts  
 ┃ ┃ ┗ 📜update-task-status.dto.ts  
 ┃ ┣ 📜task-status.enum.ts  
 ┃ ┣ 📜task.entity.ts  
 ┃ ┣ 📜tasks.controller.ts  
 ┃ ┣ 📜tasks.module.ts  
 ┃ ┗ 📜tasks.service.ts  
 ┣ 📜app.module.ts  
 ┗ 📜main.ts

위 폴더 구조를 보면 구조가 좀 간단하게 보이는데

1) main.ts가 server 띄우는 시작부분
2) app.module.ts가 root Module
3) tasks, auth 폴더가 각각의 비즈니스 모듈
4) controller.ts 가 통신을 담당하는 부분 (req res 처리)
5) service.ts 가 비즈니스 로직을 담당하는 부분
6) entity.ts가 데이터 정의된 부분
7) dto는 말그래도 Data Transfer Object 정의한 부분

뭐 이정도이다.

위처럼 대강 큰 그림 그린 상태로 각 파일을 까보면

  • @Module
// Module
@Module({
  imports: [TasksModule],
})

@Module({
    controllers: [
        TasksController,
    ],
    providers: [
        TasksServie,
        LoggerService,
    ],
})
  • @Controller
  // Controller
  @Controller('/tasks')
  export class TasksController {
      @Get()
      getAllTasks() {
          // do stuff
          return ...;
      }

      @Post()
      createTask() {
          // do stuff
          return ...;
      }
  }

@Service

  @Injectable()
  export class TasksService {
      constructor(
          @InjectRepository(Task)
          private tasksRepository: Repository<Task>,
      ) {}

      async getTasks(filterDto: GetTasksFilterDto): Promise<Task[]> {
          const { status, search } = filterDto;
          const query = this.tasksRepository.createQueryBuilder('task');

          if (status) {    
              query.andWhere('task.status = :status', { status });
          }

          if (search) {
              query.andWhere('LOWER(task.title) LIKE LOWER(:search) OR LOWER(task.description) LIKE LOWER(:search)',
              { search: `%${search}%` },
          );
      }
          const tasks = await query.getMany();
          return tasks;
      }
  }

뭐 이런식으로 되어 있다....

1. CRUD

CRUD는 먼저 인 메모리에 배열 선언해서 만들어 보면 구조 파악하기가 좋다.
그리고 Docker, PostgreSQL을 깔고 연결해주면 된다.

CRUD를 배열로 구현하고 나서, 반년만에 DB를 직접 건들여야 한다는 생각에 조금 겁이 났는데, Type ORM을 사용하니까 진짜 간단한게 구현이 가능했다. 사실 CRUD만 한거라 쿼리문 짤것도 없었지만... 쿼리문을 이해하고, Type ORM을 많이 사용하다보면 진짜 빠른 개발이 가능하겠다고 생각했다.

물론 성능 최적화를 위해선 쿼리문을 직접 잘 짜는 사람이 능력 있는 개발자겠지?

댓글