2. Boards module
1. BoardsModule
생성하기
BoardsModule
을 생성하기 위해 다음 명령어를 입력한다.
NestJS CLI를 이용하여 BoardsModule
을 생성하면 AppModule
에 자동으로 등록된다.
import { Module } from "@nestjs/common";
import { BoardsModule } from "./boards/boards.module";
@Module({
imports: [BoardsModule],
})
export class AppModule {}
2. BoardsController
생성하기
BoardController
를 생성하기 위해 다음 명령어를 입력한다. 만약 테스트용 파일을 생성하지 않을 경우 --no-spec
옵션을 추가하면 된다.
마찬가지로 NestJS CLI를 이용하여 BoardController
를 생성하면 BoardsModule
에 자동으로 등록된다.
import { Module } from "@nestjs/common";
import { BoardsController } from "./boards.controller";
@Module({
controllers: [BoardsController],
})
export class BoardsModule {}
3. BoardsService
생성하기
BoardsService
를 생성하기 위해 다음 명령어를 입력한다.
BoardsService
를 생성하면 BoardsModule
에 자동으로 등록되며, 이러한 서비스, 리포지터리 등 프로바이더를 등록한 후 사용하려면 해당 모듈 파일의 providers
배열에 추가해야 한다.
import { Module } from "@nestjs/common";
import { BoardsController } from "./boards.controller";
import { BoardsService } from "./boards.service";
@Module({
controllers: [BoardsController],
providers: [BoardsService],
})
export class BoardsModule {}
4. 모든 게시물을 가져오는 서비스/컨트롤러 만들기
NestJS 프로젝트의 비즈니스 로직은 컨트롤러가 아닌 서비스에서 구현한다. 지금은 로컬 메모리를 이용하도록 구현하고 나중에 데이터베이스를 연결할 수 있도록 구현할 것이다.
import { Injectable } from "@nestjs/common";
@Injectable()
export class BoardsService {
private boards = [];
getAllBoards() {
return this.boards;
}
}
이 서비스를 BoardsController
에 주입하기 위해서 다음과 같이 constructor
에 선언하면 된다. 물론 BoardsModule
의 providers
배열에 추가된 상태여야만 한다.
import { Controller } from "@nestjs/common";
import { BoardsService } from "./boards.service";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
}
그리고 getAllBoards()
라우트 핸들러에 @Get
데코레이터를 달아준 후 BoardsService
의 getAllBoards()
를 호출한다. 컨트롤러는 특정 URL의 진입점을 담당하며, 라우트 핸들러는 엔드포인트를 담당하는 것이라고 보면 된다.
import { Controller, Get } from "@nestjs/common";
import { BoardsService } from "./boards.service";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards() {
return this.boardsService.getAllBoards();
}
}
5. Board
모델 만들기
게시물을 생성하는 데 필요한 데이터가 어떤 것인지 정의해 주기 위해 모델을 정의한다. 이러한 모델을 정의하기 위해서는 클래스 또는 인터페이스를 이용하여 구현하면 된다. 일단 간단한 모델을 정의하기 위해 인터페이스로 구현해 보자.
export interface Board {
id: string;
title: string;
description: string;
status: BoardStatus;
}
export enum BoardStatus {
PUBLIC = "PUBLIC",
PRIVATE = "PRIVATE",
}
위의 코드에서 BoardStatus
를 Enum
타입으로 정의한 이유는 PUBLIC
또는 PRIVATE
이외의 상태가 나오면 안되기 때문이다.
이렇게 정의한 Board
모델을 다음과 같이 BoardsService
에 적용하면, 게시물 데이터에 대한 타입을 정의할 수 있게 된다. 타입을 정의하여 사용하면 린트, 오토 컴플릿 등의 타입스크립트의 유용한 기능을 사용할 수 있다.
import { Injectable } from "@nestjs/common";
import { Board } from "./board.model";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
}
마찬가지로 BoardsController
에도 Board
모델을 적용한다.
import { Controller, Get } from "@nestjs/common";
import { Board } from "./board.model";
import { BoardsService } from "./boards.service";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
}
6. 게시물을 생성하는 서비스/컨트롤러 만들기
게시물을 생성하는 서비스를 구현해 보자.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(title: string, description: string): Board {
const board: Board = {
// id: 유니크한 값
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
}
createBoard()
메서드를 구현할 때 Board
모델의 id
프로퍼티는 유니크한 값이어야 한다. 유니크한 값을 생성하기 위해 uuid
모듈을 설치한 후 사용한다.
uuid
모듈을 설치한 후 다음과 같이 id
프로퍼티에 유니크한 값을 넣어준다.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { v1 as uuid } from "uuid";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(title: string, description: string): Board {
const board: Board = {
id: uuid(),
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
}
이제 컨트롤러에서도 게시물을 생성할 수 있도록 createBoard()
라우트 핸들러를 구현한다.
import { Body, Controller, Get, Post } from "@nestjs/common";
import { Board } from "./board.model";
import { BoardsService } from "./boards.service";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
@Post("/")
createBoard(
@Body("title") title: string,
@Body("description") description: string
): Board {
return this.boardsService.createBoard(title, description);
}
}
7. DTO(Data Transfer Object)
DTO는 계층 간 데이터 교환을 위한 객체를 의미한다. DTO를 사용하는 이유는 데이터 유효성을 검사하는 데 효율적이고, 코드 관리를 용이하게 해준다. 현재 클라이언트로부터 게시물을 생성하는 요청을 받을 때 필요한 데이터는 title
과 description
이다. 이 두 데이터를 DTO로 생성하여 관리할 수 있도록 한다.
다음과 같이 src/boards
디렉터리에 dto
디렉터리를 생성한 후 CreateBoardDto
클래스를 정의한다.
export class CreateBoardDto {
title: string;
description: string;
}
CreateBoardDto
를 정의한 후 서비스와 컨트롤러 각각에 적용해 보자.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { v1 as uuid } from "uuid";
import { CreateBoardDto } from "./dto/create-board.dto";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(createBoardDto: CreateBoardDto): Board {
const { title, description } = createBoardDto;
const board: Board = {
id: uuid(),
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
}
import { Body, Controller, Get, Post } from "@nestjs/common";
import { Board } from "./board.model";
import { BoardsService } from "./boards.service";
import { CreateBoardDto } from "./dto/create-board.dto";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
@Post("/")
createBoard(@Body() createBoardDto: CreateBoardDto): Board {
return this.boardsService.createBoard(createBoardDto);
}
}
8. ID로 특정 게시물을 가져오는 서비스/컨트롤러 만들기
ID를 이용하여 특정 게시물을 가져오는 서비스와 컨트롤러를 구현해 보자.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { v1 as uuid } from "uuid";
import { CreateBoardDto } from "./dto/create-board.dto";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(createBoardDto: CreateBoardDto): Board {
const { title, description } = createBoardDto;
const board: Board = {
id: uuid(),
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
getBoardById(id: string): Board {
return this.boards.find((board) => board.id === id);
}
}
import { Body, Controller, Get, Param, Post } from "@nestjs/common";
import { Board } from "./board.model";
import { BoardsService } from "./boards.service";
import { CreateBoardDto } from "./dto/create-board.dto";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
@Post("/")
createBoard(@Body() createBoardDto: CreateBoardDto): Board {
return this.boardsService.createBoard(createBoardDto);
}
@Get("/:id")
getBoardById(@Param("id") id: string): Board {
return this.boardsService.getBoardById(id);
}
}
9. ID로 특정 게시물을 지우는 서비스/컨트롤러 만들기
ID를 이용하여 특정 게시물을 지우는 서비스와 컨트롤러를 구현해 보자.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { v1 as uuid } from "uuid";
import { CreateBoardDto } from "./dto/create-board.dto";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(createBoardDto: CreateBoardDto): Board {
const { title, description } = createBoardDto;
const board: Board = {
id: uuid(),
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
getBoardById(id: string): Board {
return this.boards.find((board) => board.id === id);
}
deleteBoard(id: string): void {
this.boards = this.boards.filter((board) => board.id !== id);
}
}
import { Body, Controller, Delete, Get, Param, Post } from "@nestjs/common";
import { Board } from "./board.model";
import { BoardsService } from "./boards.service";
import { CreateBoardDto } from "./dto/create-board.dto";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
@Post("/")
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);
}
}
10. 특정 게시물을 업데이트하는 서비스/컨트롤러 만들기
특정 게시물을 업데이트하는 서비스와 컨트롤러를 구현해 보자.
import { Injectable } from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { v1 as uuid } from "uuid";
import { CreateBoardDto } from "./dto/create-board.dto";
@Injectable()
export class BoardsService {
private boards: Board[] = [];
getAllBoards(): Board[] {
return this.boards;
}
createBoard(createBoardDto: CreateBoardDto): Board {
const { title, description } = createBoardDto;
const board: Board = {
id: uuid(),
title,
description,
status: BoardStatus.PUBLIC,
};
this.boards.push(board);
return board;
}
getBoardById(id: string): Board {
return this.boards.find((board) => board.id === id);
}
deleteBoard(id: string): void {
this.boards = this.boards.filter((board) => board.id !== id);
}
updateBoardStatus(id: string, status: BoardStatus): Board {
const board = this.getBoardById(id);
board.status = status;
return board;
}
}
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
} from "@nestjs/common";
import { Board, BoardStatus } from "./board.model";
import { BoardsService } from "./boards.service";
import { CreateBoardDto } from "./dto/create-board.dto";
@Controller("boards")
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get("/")
getAllBoards(): Board[] {
return this.boardsService.getAllBoards();
}
@Post("/")
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/status")
updateBoardStatus(
@Param("id") id: string,
@Body("status") status: BoardStatus
): Board {
return this.boardsService.updateBoardStatus(id, status);
}
}