Nest.js 배워보기-1

jonghyun.log·2022년 2월 1일
12
post-thumbnail

nest.js를 배워보고 혼자 정리하기 위해 작성한 글입니다. 틀린 내용이나 오타가 있을수 있습니다. 지적해주시면 감사합니다 ㅎㅎ

Nest.js란?

Nest(NestJS)는 효율적이고 확장 가능한 Node.js 서버 측 애플리케이션을 구축하기 위한 프레임워크입니다. 프로그레시브 JavaScript를 사용하고 TypeScript 로 구축되고 완벽하게 지원하며 (그러나 여전히 개발자가 순수 JavaScript로 코딩할 수 있음) OOP(객체 지향 프로그래밍), FP(기능 프로그래밍) 및 FRP(기능 반응 프로그래밍)의 요소를 결합합니다.

내부적으로 Nest는 Express (기본값)와 같은 강력한 HTTP 서버 프레임워크를 사용하며 선택적으로 Fastify 도 사용하도록 구성할 수 있습니다.

Nest는 이러한 일반적인 Node.js 프레임워크(Express/Fastify)보다 높은 수준의 추상화를 제공하지만 해당 API를 개발자에게 직접 노출합니다. 이를 통해 개발자는 기본 플랫폼에서 사용할 수 있는 수많은 타사 모듈을 자유롭게 사용할 수 있습니다.

네스트 공식문서 링크텍스트 출처

쉽게말하면 네스트는 기존의 자유로운 node.js 개발 환경에서 보다 안정적인 개발 환경을 구축하기 위해 만들어진 프레임 워크라고 할 수 있고 java기반의 spring과 유사하다.
(네스트는 기본적으로 typescript를 사용한다.)

Nest.js 시작하기

먼저 터미널을 연뒤 다음의 명령어를 입력해야하는데

$ npm i -g @nestjs/cli 
$ nest new project-name

네스트 공식문서 링크텍스트 출처

네스트를 시작하려면 먼저 위의 명령어를 사용해야한다.

첫줄의 코드가 의미하는것은 global(-g) 환경으로 npm(NodePackageManger)에게
nestjs/cli(Nest 프로젝트를 생성해주는 프로그램)을 설치하라는 의미이고
(node.js가 기존에 설치되어있어야합니다.)

두번째 코드의 의미는 nestjs/cli한테 project-name의 이름으로 프로젝트를 생성해달라는 의미이다.
(첫번째 명령어를 실행하고 프로젝트를 만들 경로로 이동한뒤 두번째 명령어로 프로젝트를 생성해주면 된다.)

프로젝트를 생성해주고 나면 위와같이 자동으로 프로젝트를 생성해줄것이다.

먼저, 각 파일들이 무슨 역할을 하는지 간단한게 알아보자!

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();

main.ts파일은 네스트 애플리케이션을 생성해주고(이때, AppModule이라는것을 생성해준다.)
네스트 애플리케이션의 시작점 역할을 해준다.

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 {}

nest.js는 하나이상의 모듈이 필요한데, 모듈은 nest.js 애플리케이션을 구성하는 밀접한 기능들을 묶어놓은 하나의 집합이다. 만약 게시판 기능을 만든다고 하면 게시판을 관리하는 BoardModule, 사용자 인증을 처리하는 AuthModule 그리고 각 모듈을 다 묶는 루트 모듈(여기서는 AppModule)이 있다.
좀 더 자세한 내용은 뒤에서 알아보자.
여기서는 일단 AppModulenest.js 애플리케이션의 시작점이라고 생각하면 된다.

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();
  }
}

컨트롤러는 MVC모델의 C즉 Controller인데 클라이언트에서 어떤 요청을 보내오면(여기서는 브라우저가 된다.) 컨트롤러로 간뒤 그 요청에 맞는 동작들을 실행해준다. main.ts 에서 기본 설정값인 3000번 포트로 되어있으므로 localhost:3000으로 접속하게되면 get요청에 의해 app.controller.ts
getHello() 메서드로 이동한뒤 appService.getHello() 라는 메서드를 호출하게 된다.
(@Get() 이부분은 데코레이터라는 네스트만의 문법을 사용해서 어떠한 요청인지를 나타내주는 부분인데 여기서는 get요청을 의미하고 공백은 '/'를 의미하게 된다.)

위의 클래스에서 constructor(private readonly appService: AppService) 이 부분은
AppService에서 내보내준 코드를 AppController에서 사용할 수 있게 해주는 역할을 해준다.
이를 종속성 주입이라고 하는데 nest.js에서는 종속성 주입을 이런식으로 constructor() 안에서 하게 된다.

app.service.ts

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

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

위의 컨트롤러에서 get요청을 받았을때 appService.getHello() 메서드를 호출했었는데 여기서
appService 부분이 이 파일을 의미한다. service파일은 데이터를 처리해주는 역할을 한다.
물론 service가 없이 controller에서 모든것을 처리해도 되겠지만, 로직이 길어지면 유지보수에도 어렵기 때문에 nest.js에서는 따로 service파일을 만들어서 로직을 분리해서 관리해주는 관행이 있다.
위의 파일에서는 'Hello World!'를 보내주게 된다.
(@injectable() 이 부분도 데코레이터의 일종인데 다른 코드에서 AppService class를 사용할 수 있게 해주는 역할을 해준다. 자바스크립트의 export 와 비슷한 역할을 한다고 생각해주면 될 거 같다.)

app.controller.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';

describe('AppController', () => {
  let appController: AppController;

  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [AppService],
    }).compile();

    appController = app.get<AppController>(AppController);
  });

  describe('root', () => {
    it('should return "Hello World!"', () => {
      expect(appController.getHello()).toBe('Hello World!');
    });
  });
});

이 파일은 각종 테스트를 할때 사용되는 용도로 사용된다. 아직 이것을 사용할 단계가 아니라 일단 넘어가겠다.

만든 프로젝트 실행해보기

package.json

"scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },

이 파일은 각종 설정에 관한 것들을 모아놓은 파일인데 scripts안의 startstart:dev를 한번 눈여겨 보자 이것들은 일종의 단축키를 모아놓은 것인데
npm run 명령어 부분에 위의 명령어들을 넣어주면 각 항목 오른쪽에 있는 명령어로 대체되어서 입력이 된다. 예를 들어 터미널에 npm run start 를 입력 하게 되면 자동으로 nest start
로 바꿔서 입력이 되는 방식이다.
우리는 코드를 수정하면서 어떻게 되는지 봐줘야 하기 때문에 개발할때는 npm run start:dev를 이용하면 된다.
(--watch 옵션이 자동으로 코드가 변환되는것을 현재 실행되는 애플리케이션에 반영해준다.)

이제, 명령어를 입력하고 브라우저에서 localhost:3000으로 접속하면

Hello world! 가 잘 나오는 것을 확인해 볼 수 있다!

마치며

오늘은 프로젝트를 처음 만들고 각 파일들이 의미하는게 뭔지 알아봤는데 아직은 갈길이 멀다. 다음엔 좀 더 깊은 내용까지 알아보자!

3개의 댓글

comment-user-thumbnail
2022년 2월 4일

많은 도움 되었습니다.

답글 달기
comment-user-thumbnail
2022년 2월 4일

nest 너무 어려워요 ~!

답글 달기
comment-user-thumbnail
2022년 2월 4일

갈길이 머네요...

답글 달기