[Nest.js] Bun 환경에서 Nest.js Init, 구조 모듈화

Express + TypeScript 사용하여 bun 환경에서 프로젝트 :

1. bun --help를 통해 bun설치여부 확인

2. bun init -y 로 기본 프로젝트 

3. bun run index.ts

Hello via Bun!

 

출력 확인하면 끝.

Express 는 자유롭다.하지만 그 자유로움에는 책임이 따른다.. 

 

NestJS ?

NestJS는 서버 개발 시의 아키텍처를 누구든 비슷하게 설계하도록 아키텍처 문제를 해결하는 데 중점을 두고 있다.

 

- Node.JS 에서 실행하는 서버사이드 프레임워크

- 타입스크립트 완벽 지원

- 자바스크립트의 최신 스펙을 사용하므로, 바닐라 자바스크립트를 사용한다면 babel 사용이 필수

- HTTP요청 부분은 추상화된 코드를 제공해, 익스프레스와 Fastify를 사용할 수 있다. 

 

 


Nest.js + TypeScript 사용하여 Node.js 환경에서 프로젝트 init

//node.js
npm install -g @nestjs/cli
nest new blog
npx ts-node-dev src/main.ts

파일이 변경될 때마다 main.ts 를 TypeScript로 컴파일하여 자동으로 다시 컴파일되고 실행되도록 설정해준다. 
nodemon과 유사

 

Nest.js + TypeScript 사용하여 bun 환경에서 프로젝트 init

//bun
bun create nest 프로젝트이름

 

 

cli 까지 한번에 처리된다. 아래처럼 폴더구조 생성되는 것을 확인할 수 있다.

bun create nest typeBlog 실행 뒤 폴더구조 모습

 

린트 설정

아래링크 참고

https://cosanam.com/posts/TypeScript-%EB%9F%B0%ED%83%80%EC%9E%84-Bun%EA%B3%BC-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8/

bun add -d eslint eslint-plugin-prettier eslint-config-prettier prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript

 

모듈화 구조 수정

bun create nest 명령을 사용했을 때 기본 생성되는 구조는 두 가지 이다. 

 

1. blog/src/app.module.ts

import { Module } from '@nestjs/common';

@Module({})
export class AppModule {}

 

 

2. blog/src/main.ts

import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

 

어떤 프로그램이든 최초로 실행되는 함수가 필요하다. NestJS의 서버 역시 가동하려면 최초 진입점이 필요하다. NestJS에서는 이름을 bootstrap으로 이름 짓는 것이 관례이다. NestFactory는 사실 NestFactoryStatic 클래스이며, create()함수에 루트 모듈을 넣어서 NestApplication객체를 생성한다. 

 

 

프로젝트의 진입 순서는 main.ts -> App.module -> 컨트롤러 Controller -> 서비스 Service -> 레포지토리 Repository 

이므로 다음과 같이 수정해주었다.

 

module, controller, service, repository 수정

 

app.module.ts

import { Module } from '@nestjs/common';
import {BlogController} from './blog.controller';
import {BlogService} from './blog.service';
@Module({
    imports: [], //외부 모듈 호출시 사용
    controllers : [BlogController],
    providers : [BlogService],
})
export class AppModule {}

 

 

blog.controller.ts

import {Controller} from '@nestjs/common'

@Controller('blog')
export class BlogController{}

 

 

blog.service.ts

export class BlogService{}

 

이렇게 import 될 수 있게 기본 구조를 만들면 에러없이 동작한다. 

 

 

interface를 이용해 Repository 만들기 

 

blog.model.ts

export interface PostDto{
    id : string;
    title : string;
    content : string;
    name : string;
    createdDt : Date;
    updatedDt? : Date;
}

 

interface를 활용하여 사용하여 DTO를 작성하였다.

 

@Controller('blog')
export class BlogController{
    blogService : BlogService;
    constructor(){
        this.blogService = new BlogService();
    }
}

 

DB 연결이 아직이라서 위처럼 Controller에 생성자를 이용해 Service계층과 연결해주었다. 

 

(상세 코드 : https://github.com/wjdwwidz/TypeBlog

 

 

Bun을 사용하니 수많은 install들이 필요 없어져 매우 편리하다. 다만 bun 관련 에러들은 정보량이 node만큼은 많지 않다는 단점이 있다..

 

 


참고 : Nest.js 표준 예외 처리

localhost:3000

 

bun run main.ts 로 localhost:3000서버를 실행하면 메인 컨트롤러가 없어 아래와 같은 객체를 넘겨준다. 

{
"message":"Cannot GET /",
"error":"Not Found",
"statusCode":404
}

 

statusCode를 정의해준 바가 없는데 404를 넘겨주길래, 처음에는 bun 에서 자동으로 처리되는 건가 했는데, 찾아보니 NestJS에서 기본적으로 제공해주는 HTTP exception인 NotFoundException에서 넘겨준 status라고 한다.

 

더보기

Nest에는 모든 예외를 처리하는 자체 예외 레이어를 가지고 있다. 애플리케이션 코드에서 예외 처리를 하지 않아도 알아서 보기 쉬운 형식으로 에러를 변환하여 전송한다.

표준 예외 처리는 내장된 전역 예외 필터에 의해 수행되며, 예외 필터는 HttpException 의 예외를 다룬다.

HttpException도 아니고, HttpException을 상속받지도 않은 에러의 경우 내장 예외 필터가 위와 같은JSON응답을 생성한다고 한다. 

 

 

라우트 핸들러 내부에서 예외처리

만약 아래와 같은 라우트 핸들러에서 예외를 던지면 에러를 다음처럼 응답한다. 

  @Get()
  getAllCat() {
    throw new HttpException('api is broken', 401);
    return 'all cat';
  }

 

{
  "statusCode": 401,
  "message": "api is broken"
}

statusCode와 message가 강제되어서 출력되는 것을 확인할 수 있다. NestJS가 제공하는 대로 예외를 처리할 수도 있지만, 서비스의 형태에 따라 에러를 핸들링할 때 커스텀을 할 수도 있다.