1. NestJs 기본 구조
지난 포스팅에서는 프로젝트 만들기까지 해 보았습니다. 그럼 만들어진 NestJs 프로젝트의 각 폴더 및 파일들이 어떤 역할을 하는 것인지 살펴보도록 하겠습니다!
프로젝트를 만들면 아래와 같이 파일들이 생성되었는데요! 하나하나 살펴볼게용
eslintrc.js
개발자들이 특정한 규칙을 가지고 코드를 깔끔하게 짤 수 있게 도와주는 라이브러리입니다.
타입스크립트를 쓰는 가이드라인을 제시해 주고, 문법에 오류가 나면 알려주는 역학을 합니다.
prettierrc
주로 코드 형식을 맞추는 데사용합니다.
작은따옴표를 사용할지, 큰 따옴표를 사용할지, Indent값을 2로 줄지, 4로 줄지 등등,,,
에러를 찾는 것이 아닌 코드 포맷터 역할을 합니다.
nest-cli.json
nest 프로젝트를 위해 특정한 설정을 할 수 있는 Json 파일입니다.
tsconfig.json
어떻게 타입스크립트 컴파일할지를 설정합니다
tsconfig.build.json
tsconfig.json의 연정선상 파일이며, build를 할 때 필요한 설정들입니다.
"excludes"에서는 빌드할 때 필요 없는 파일들을 명시합니다. 예를 들어 테스트코드 같은 것들이 있겠죠?
package.json
build: 운영환경을 위한 빌드
format: 린트 에러가 났을지 수정
start: 앱 시작
src폴더
대부분의 비즈니스 로직이 들어가는 곳입니다.
- main.ts : 앱을 생성하고 실행
- app.module.ts : 앱 모듈을 정의
2. 기본 구조에서 살펴보는 NestJS 로직 흐름
Express와 비교해서 생각해 보면 됩니다! 근데 제가 보기에는 Spring과 더 비슷하다는 느낌이 들긴 했어요..!
3. NestJS 모듈(@Module()) 이란?
NestJS를 사용해서 만드는 앱구조
App Module 안에 예를 들어서 BoardModule과 AuthModule이 있으면 각 모듈 안에 Controller, Entity, Service 등이 있습니다.
그래서!!! 모듈이 뭐냐??
모듈은 @Module() 데코레이터로 주석이 달린 클래스입니다. @Module() 데코레이터는 Nest가 애플리케이션 구조를 구성하는 데 사용하는 메타데이터를 제공합니다!
메타데이터??
메타데이터는 데이터에 대한 데이터입니다. 즉, 다른 데이터를 설명하거나 해석하는 데이터입니다. 프로그래밍 콘텍스트에서 메타데이터는 소프트웨어 엔터티의 구조, 동작, 특성 등을 설명하는 정보를 말합니다.
NestJS에서의 @Module() 데코레이터가 제공하는 메타데이터는 애플리케이션의 구조를 정의하고 구성하는 데 사용됩니다. 이 메타데이터는 NestJS 프레임워크에게 해당 클래스가 Nest 모듈임을 나타내며, 해당 모듈이 어떤 컨트롤러, 서비스, 및 다른 모듈과 관련이 있는지를 정의합니다.
NestJS에서 모듈은 애플리케이션의 기능을 조직화하고 각 부분 간에 분리되고 결합되는 방법을 제공합니다. @Module() 데코레이터는 이러한 모듈의 동작 및 관계를 정의하는 데 사용되며, 이는 의존성 주입 및 애플리케이션의 구조를 관리하는 데 필수적입니다.
간단히 말해, @Module() 데코레이터는 NestJS 애플리케이션의 구조를 구성하고 설명하는 데 사용되는 메타데이터를 제공합니다. 이를 통해 NestJS는 애플리케이션의 부품을 어떻게 조립해야 하는지 이해하고 관리할 수 있습니다.
소스코드를 이용해서 모듈 만들기
import { Module } from '@nestjs/common';
import { BoardsController } from './boards.controller';
import { BoardsService } from './boards.service';
@Module({
controllers: [BoardsController],
})
export class BoardsModule {}
이렇게 BoardModule안에 BoardController와 BoardService를 넣어 주시면 됩니다!
Board Module 생성하기
nest-cli로 모듈 생성을 할 수 있습니다!
"nest g module boards"
nest: using nestcli
g: generate
module: schematic that i want to create
boards: name of the schematic
이렇게 명령어를 터미널에 치면!
boards/boards.module.ts 파일이 생성됩니다!
boardModule을 사용하기 위해서는 app.module.ts에 등록해주어야 합니다!
import { Module } from '@nestjs/common';
import { BoardsModule } from './boards/boards.module';
@Module({
imports: [BoardsModule],
})
export class AppModule {}
4. NestJS Controllers란?
Controller?
컨트롤러는 들어오는 요청을 처리하고 클라이언트에 응답을 반환합니다. (구조가 spring이랑 비슷하게 느껴졌습니다!)
컨트롤러는 @Controller 데코레이터(spring에서 어노테이션과 비슷하다고 생각되었습니다,,)로 클래스를 데코레이션 하여 정의됩니다.
@Controller('/boards')
export class BoardsController {
}
데코레이터는 인자를 (여기서는 '/boards') Controller에 의해서 처리되는 "경로"로 받습니다!
Handler?
핸들러는 @Get, @Post, @Patch, @Put, @Delete등과 같은 HTTP Method 데코레이터로 장식된 컨트롤러 클래스 내의 메서드입니다.
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { BoardsService } from './boards.service';
import { Board, BoardStatus } from './board.model';
import { CreateBoardDto } from './dto/create-board.dto';
import { BoardStatusValidationPipe } from './pipes/board-status-validation.pipe';
@Controller('/boards')
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get()
getAllBoard(): Board[] {
return this.boardsService.getAllBoards();
}
@Post()
@UsePipes(ValidationPipe)
createBoard(@Body() createBoardDto: CreateBoardDto): Board {
return this.boardsService.createBoard(createBoardDto);
}
@Get('/:id')
getBoardById(@Param('id') id: string): Board {
return this.boardsService.getBoardById(id);
}
@Delete('/:id')
deleteBoard(@Param('id') id: string): void {
this.boardsService.deleteBoard(id);
}
@Patch('/:id')
updateBoardStatus(
@Param('id') id: string,
@Body('status', BoardStatusValidationPipe) status: BoardStatus,
) {
return this.boardsService.updateBoardStatus(id, status);
}
}
Board Controller 생성하기
"nest g controller boards --no-spec"
nest: using nestcli
g: generate
controller: controller schematic
boards: name of the schematic
--no-spec: 테스트 크도를 위한 소스코드 생성 x(Default로 자동으로 생성됩니다)
이렇게 nest-cli로 controller를 만들면 자동으로 boards폴더를 찾고-> boards폴더 안에 controller파일을 생성-> boards폴더 안에 module 파일 찾기-> module파일 안에다가 controller를 넣어줍니다!
5. NestJS Providers, Service란?
Providers??
대부분의 Nest 클래스는 서비스, 레포지토리, 팩토리, 헬퍼 등 프로바이더로 취급될 수 있습니다. 프로바이더의 주요 아이디어는 종속성을 주입할 수 있다는 것입니다.(이 점이 spring에서의 @Autowired(의존성주입)과 비슷하다고 느껴졌습니다!)
즉, 객체는 서로 다양한 관계를 만들 수 있으며 객체의 인스턴스를 연결하는 기능은 대부분 Nest런타임 시스템에 위임될 수 있습니다.
Service??
@Injectable 데코레이터로 감싸져서 모듈에 제공되며, 이 서비스 인스턴스는 애플리케이션 전체에서 사용될 수 있습니다.
서비스는 컨트롤러에서 데이터의 유효성체크를 하거나 데이터베이스에 아이템을 생성한느 등의 작업을 하는 부분을 말합니다!(ExpressJs에서 Controller의 역할과 비슷하다고 생각되었습니다!)
Service를 Controller에서 이용할 수 있는 방법(Dependency Injection)
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { BoardsService } from './boards.service';
import { Board, BoardStatus } from './board.model';
import { CreateBoardDto } from './dto/create-board.dto';
import { BoardStatusValidationPipe } from './pipes/board-status-validation.pipe';
@Controller('/boards')
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get('/:id')
getBoardById(@Param('id') id: string): Board {
return this.boardsService.getBoardById(id);
}
}
여기에서 보면 BoardService를 constructor 클래스 내에서 가져오고 있습니다. 이게 의존성이 주입된 거라 보면 됩니다. 그런 후에 private 문법을 사용하고 있습니다. 이렇게 해서 boardService를 정의해서 Controller안에서 사용할 수 있게 만들었습니다. 이렇게 할 수 있는 이유는 타입스크립트의 기능을 이용해서 종속성을 타입으로 해결할 수 있기 때문입니다!
Provider등록하기
import { Module } from '@nestjs/common';
import { BoardsController } from './boards.controller';
import { BoardsService } from './boards.service';
@Module({
controllers: [BoardsController],
providers: [BoardsService],
})
export class BoardsModule {}
boards.module.ts파일 내의 providers에 등록해 주면 됩니다!
Boards Service 만들기
앞에서 컨트롤러와 같이 서비스도 nest-cli로 생성할 수 있습니다.
service안에서는 대부분 데이터베이스 관련 로직을 처리합니다!
"nest g service boards --no-spec"
nest: using nestcli
g: generate
service: service schematic
boards: name of the schematic
--no-spec: 테스트를 위한 소스코드 생성 x
=> 이렇게 cli를 이용해서 service를 생성하면 boards.service.ts파일이 생성됩니다.
import { Injectable } from '@nestjs/common';
@Injectable()
export class BoardsService {
}
이 생성된 파일 안에는 Injectable 데코레이터가 있으며 NestJs는 이것을 이용해서 다른 컴포넌트에서 이 서비스를 재사용할 수 있게 해 줍니다!
그리고 Cli로 Service 생성 시에는 module에도 자동으로 Service가 추가됩니다.
Board Service를 Board Controller에서 이용할 수 있게 해 주기(Dependency Injection)
NestJs에서 의존성 주입은 클래스의 Constructor안에서 이루어집니다. 위에서 봤었죠? 그런데 여기에는 여러 코드가 압축되어 있습니다.
@Controller('boards')
export class BoardsController{
boardService: BoardService;
constructor(boardsService: BoardsService){
this.boardsService=boardsService;
}
}
1. boardsService 파라미터에 BoardsService 객체를 타입으로 지정해 줍니다.
2. 이 boardsService 파라미터를 BoardsController 클래스 안에서 사용하기 위해서 this.boardsService 프로퍼티에 boardsService파라미터를 할당해 줍니다.
3. 하지만 타입스크립트에서는 선언한 값만 객체의 프로퍼티로 사용가능하기 때문에 위에 boardsServcie: BoardsService로 선언해 줍니다.
4. 이렇게 갖게 된 boardsService 프로퍼티를 이용해서 BoardsController 클래서안에서 활용을 할 수가 있습니다.
접근 제한자를 이용해서 소스 간단하게 하기
접근제한자(public, protected, private)를 생성자(constructor) 파라미터에 선언하면 접근 제한자가 사용된 생성자 파라미터는 암묵적으로 클래스 프로퍼티로 선언됩니다!
@Controller('boards')
export class BoardsController{
constructor(private boardsService: BoardsService){}
getAllTask(){
this.boardsService.
}
}
Private를 사용하면?
spring과 같이 private로 선언되었기 때문에 boardsService 프로퍼티는 BoardsController클래스 내부에서만 사용가능합니다!
이렇게 NestJs의 기본구조에 대해서 정리해 보았습니다! 전체적인 흐름 로직은 Express와 비슷한데, 저는 개인적으로 Spring과 더 비슷하다고 느껴졌습니다 ㅎㅎ
아직 조금만 배웠지만 spring을 했다면 충분히 쉽게 배울 수 있는 프레임워크인 듯합니다! 그리고 기본적인 메서드도 많이 내장되어 있어 편 라하기도 하네요!
'NestJs' 카테고리의 다른 글
NestJs 최신버전 업데이트 및 스터디 시작 (0) | 2024.02.06 |
---|---|
[NestJs] NestJs 소개, CLI설치하고 프로젝트 만들기 (1) | 2024.01.29 |