Blog

[NestJS] 3. NestJS CRUD Operation 개발

Category
Author
citeFred
citeFred
PinOnMain
1 more property
NestJS, TypeORM 이해하기
Table of Content

1. 게시글 엔터티 설계

엔터티란?
엔터티(Entity)는 업무에 필요하고 유용한 정보를 저장하고 관리하기 위한 "어떤 것(Thing)"
"어떤 것"이라고 부르는 것처럼 엔터티는 추상적인 의미를 가지며 학교나 학생처럼 현실 세계에서 눈에 보이는 개념일 수도 있고 주문이나 결제처럼 눈에 보이지 않는 개념일 수도 있다.
엔터티는 쉽게 말해 실체, 객체라고 생각할 수 있다.
엔터티는 어떠한 객체이며 속성을 갖는다.
객체가 가지고 있는 정보, 특징은 속성이 된다.
더이상 분리 되지 않는 최소 데이터 단위를 속성이라 한다.(ex:이름, 제목, 나이, 키 등)
두개 또는 그 이상의 엔터티들은 관계를 갖는다.
다른 엔터티와의 존재에 의한 관계(ex:직원엔터티는 부서엔터티에 소속된다. 정적인 관계)
다른 엔터티와의 행위에 의한 관계(ex:고객엔터티는 상품엔터티를 주문한다. 동적인 관계)
게시글이 가지게되는 속성은 어떤것들이 있을까?
id : 게시글의 번호(고유번호) - 숫자
author : 게시글 작성자 - 문자
title : 게시글의 제목 - 문자
contents : 게시글의 내용 - 문자
status : 공개 상태 - 공개 or 비공개
board.entity.ts
nestjs/cli 명령어로는 entity 파일의 자동 generation을 지원하지 않는다.
따라서 수동으로 파일을 생성해준다.
아래와 같이 위 설계한 속성들을 Board 클래스에 정의해준다.
status는 BoardStatus라는 ENUM 클래스를 사용
import { BoardStatus } from "./board-status.enum"; export class Board { id: number; author: string; title: string; contents: string; status: BoardStatus; }
TypeScript
복사
board-status.enum.ts
ENUM 클래스는 열거형(여러개)를 다룰 때 사용되는 클래스이다.
카테고리, 장르, 유형, 타입과 같은 종류가 열거되는 것들에서 자주 사용되는 클래스이다.
아래와 같이 게시글의 상태를 PUBLIC 또는 PRIVATE로만 선택 될 수 있도록 정의해준다.
해당 ENUM 클래스 자체가 위 board.entity.ts 에서 import 되어야 한다.
export enum BoardStatus { PUBLIC = 'PUBLIC', PRIVATE = 'PRIVATE' }
TypeScript
복사

2. READ 1 - 모든 게시글을 조회하는 기능

boards.service.ts
데이터베이스로부터 게시글을 가져오는 비지니스 로직 부분이다.
실제 데이터베이스 연결 전 로컬 메모리를 사용하는 배열로 임시 데이터베이스로 시작
boards[] 배열은 임시 데이터베이스이며 private 접근제어자를 통해서 BoardsService 클래스를 통해서만 접근 가능 하도록 선언한다.
getAllBoards() 메서드를 통해서 데이터베이스의 내용(배열이므로 리스트 형태)을 반환한다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 // 전체 게시글 조회 getAllBoards(): Board[] { // 반환 타입 Board[] 배열 return this.boards; } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
GET 방식 HTTP Method를 받을 수 있는 @Get() 데코레이터를 작성하고 ('/') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
해당 컨트롤러 자체의 공통 엔드포인트는 클래스에 작성된 @Controller(’boards’)/boards 프리픽스가 붙으며 내부 메서드에서 추가 엔드포인트를 지정하게 된다.
따라서 해당 메서드는 http://localhost:3000/api/boards/ URL의 GET 요청을 처리하게 된다.
메서드 명칭은 getAllBoard()로 지정했다.
요청에대한 반환(응답)은 boardsServicegetAllBoards() 메서드를 호출하여 그 반환 데이터를 응답하게 된다.
따라서 생성자 주입을 통해서 BoardsService 를 주입받아야 해당 인스턴스의 메서드를 사용 할 수 있다.
import { Controller, Get } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} @Get('/') // GetMapping 핸들러 데코레이터 getAllBoard(): Board[] { // 반환 타입 Board[] 배열 return this.boardsService.getAllBoards(); } }
TypeScript
복사
아래 테스트는 게시글 작성 기능 구현 이후에 확인 할 수 있다.
this는 현재 클래스(BoardsController)를 지칭한다.
위 생성자 주입 코드를 명시적으로 풀어 쓰면 다음과 같다.
import { Controller, Get } from '@nestjs/common'; import { BoardsService } from './boards.service'; @Controller('api/boards') export class BoardsController { // 필드 멤버 선언 private boardsService: BoardsService; // 생성자 주입(DI) constructor(boardsService: BoardsService){} @Get('/') // GetMapping 핸들러 데코레이터 getAllBoard(){ return this.boardsService.getAllBoards(); } }
TypeScript
복사
하지만 코드의 중복을 줄이고자 위 처럼 표현하여 필드 생성과 초기화를 동시에 하는 첫번째 방법을 사용하자.
Spring에서는 필드에 private 접근제어자와 함께 final 로 불변성을 유지하던데, Typescript에서는 이것을 고려하지 않는가?
Java의 final로 초기화 이후에 변경 할 수 없도록 하는 것은 좋은 접근
하지만 Typescript에서는 관례적이지 않은 조치이긴 하다.
개발자가 명시적으로 불변성을 원할 경우에만 사용이 필요할 경우 readonly 키워드를 사용하는 방법이 있다.
import { Controller, Get } from '@nestjs/common'; import { BoardsService } from './boards.service'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private readonly boardsService: BoardsService){} @Get('/') // GetMapping 핸들러 데코레이터 getAllBoard(){ return this.boardsService.getAllBoards(); } }
TypeScript
복사
위 코드에서 boardsService 필드는 readonly로 선언되었기 때문에, 생성자에서 초기화된 이후에는 변경할 수 없어 불변성을 보장 할 수 있다.

3. CREATE - 게시글을 작성하는 기능

boards.service.ts 게시글을 작성하고 데이터베이스에 저장하는 비지니스 로직이 추가되었다.
createBoard() 메서드는 파라미터로 author, title, contents 를 받아서 함수에서 사용된다.
Board 클래스 타입의 board 변수에는 id, author, title, contents, status가 할당되어 게시글 객체가 생성된다.
id는 게시글의 고유번호로 임시로 1씩 증가하는 연산을 사용했다.
author, title, contents는 파라미터로 넘어온 값들이 할당된다.
status는 게시글의 공개상태로 임시로 공개 상태인 PUBLIC으로 하드코딩 되어 있다.
위 필드 값들을 가진 board 객체는 push를 통해 임시 데이터베이스인 board[] 배열에 저장된다.
저장 후 board 객체를 반환한다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 // 게시글 작성 createBoard(author: string, title: string, contents: string) { const board: Board = { id: this.boards.length + 1, // 임시 Auto Increament author, title, contents, status: BoardStatus.PUBLIC } this.boards.push(board); return board; } // 전체 게시글 조회 getAllBoards(): Board[] { // 반환 타입 Board[] 배열 return this.boards; } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
POST 방식 HTTP Method를 받을 수 있는 @Post() 데코레이터를 작성하고 ('/') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
따라서 해당 메서드는 http://localhost:3000/api/boards/ URL의 POST 요청을 처리하게 된다.
메서드 명칭은 createBoard()로 지정했다.
@Body() 데코레이터를 통해 HTTP 요청에 담긴 데이터를 가져 올 수 있다.
ex: @Body(’title’) 처럼 key값으로 요청 바디에 담긴 데이터의 값을 가져 올 수 있음
author, title, contents 3개의 값을 service 계층으로 전달한다.
요청에대한 반환(응답)은 boardsServicecreateBoard() 메서드를 호출하여 그 반환 데이터를 응답하게 된다. (→ 결과, 저장된 board 객체가 반환 되어 클라이언트로 응답하게 된다.)
import { Body, Controller, Get, Post } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} // 게시글 작성 기능 @Post('/') // PostMapping 핸들러 데코레이터 createBoard( @Body('author') author: string, @Body('title') title: string, @Body('contents') contents: string) { return this.boardsService.createBoard(author, title, contents) } // 게시글 조회 기능 @Get('/') // GetMapping 핸들러 데코레이터 getAllBoard(): Board[] { // 반환 타입 Board[] 배열 return this.boardsService.getAllBoards(); } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행
DTO란? 복습
DTO(Data Transfer Object)는 데이터 전송 및 이동을 위해 생성되는 객체를 의미
Client에서 보내오는(요청) 데이터를 객체로 처리할 때 사용
서버의 계층간의 이동, 다시 Client로 반환 할 때도 사용
추후, DTO에서 유효성 검사를 수행하는 것은 애플리케이션의 데이터 무결성을 보장하고, 중복된 코드 작성을 줄이며, 일관성을 유지하는 데 중요한 역할
클라이언트에서 수신한 데이터가 적절한 형식과 조건을 만족하는지 확인하는 것은 DTO의 책임
유지보수적 측면에서도 프론트엔드측 또는 백엔드서버측 속성 수정에 유연하게 대처 가능
DTO를 사용하도록 리팩토링
현재 프로젝트는 @Body() 데코레이터를 통해 HTTP 요청에 담긴 데이터를 가져오고 있다.
하지만 어떤 객체의 필드가 수십개라면? 실제로 아래처럼 나타날 가능성이 있다.
따라서 DTO를 통해서 아래와 같은 문제점을 해결하고자 한다.
createBoard( @Body('author') author: string, @Body('title') title: string, @Body('contents') contents: string @Body.... @Body.... @Body.... @Body.... @Body.... @Body.... ) { return this.boardsService.create
TypeScript
복사
/boards/dto 폴더 생성
create-board.dto.ts 생성
명명 규칙은 해당 DTO의 기능, 리소스가 명확하게 드러나도록 하는 것이 일반적인 관례
Spring은 BoardsRequestDto.java 같은 표현이 관례였던것과 조금 차이점이 있음
export class CreateBoardDto { author: string; title: string; contents: string; }
TypeScript
복사
DTO로 계층간 이동에 적용하기 위해서 Controller, Service 계층의 소스코드 수정도 필요하다.
boards.controller.ts
@Body로 1개씩 받아오던 것들이 DTO 객체를 활용하는 방식으로 변경되었다.
import { Body, Controller, Get, Post } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} // 게시글 작성 기능 @Post('/') // PostMapping 핸들러 데코레이터 createBoard(@Body() createBoardDto: CreateBoardDto) { return this.boardsService.createBoard(createBoardDto) } // 게시글 조회 기능 @Get('/') // GetMapping 핸들러 데코레이터 getAllBoard(): Board[] { // 반환 타입 Board[] 배열 return this.boardsService.getAllBoards(); } }
TypeScript
복사
boards.service.ts
이제 DTO를 통해서 author, title, contents 필드 값들을 가져 올 수 있다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 // 게시글 작성 createBoard(createBoardDto: CreateBoardDto) { const {author, title, contents} = createBoardDto; const board: Board = { id: this.boards.length + 1, // 임시 Auto Increament author, title, contents, status: BoardStatus.PUBLIC } this.boards.push(board); return board; } // 전체 게시글 조회 getAllBoards(): Board[] { // 반환 타입 Board[] 배열 return this.boards; } }
TypeScript
복사

4. READ 2 - 특정 번호 게시글을 조회하는 기능(Path Variable)

boards.service.ts 특정 id의 게시글을 조회하는 비지니스 로직이 추가되었다.
getBoardDetailById() 메서드는 파라미터로 id를 받아서 메서드에서 사용된다.
find() 메서드를 통해서 데이터베이스에 저장된 게시글의 id가 파라미터로 받아온 id와 동일한 경우 해당 게시글을 board 객체로 조회한다.
조회된 board 객체가 반환된다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 ... // 특정 번호의 게시글 조회 getBoardDetailById(id: number): Board { return this.boards.find((board) => board.id == id); } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
GET 방식 HTTP Method를 받을 수 있는 @Get() 데코레이터를 작성하고 ('/:id') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
파라미터 부분에서 @Param(’id’) 를 선언함으로써 Path Variable(경로 변수)를 사용 할 수 있다.
따라서 해당 메서드는 http://localhost:3000/api/boards/1 과 같은 게시글 번호를 Path Variable로 받는 URL의 GET 요청을 처리하게 된다.
메서드 명칭은 getBoardDetailById()로 지정했다.
메서드에 경로 변수로 받아온 id 값을 전달
요청에대한 반환(응답)은 boardsServicegetBoardDetailById(id) 메서드에 경로 변수로 받아온 id 값을 전달하며 호출하여 그 반환 데이터를 응답하게 된다. (→ 결과, 저장된 board 객체가 반환 되어 클라이언트로 응답하게 된다.)
import { Body, Controller, Get, Param, Post } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 번호의 게시글 조회 @Get('/:id') getBoardDetailById(@Param('id') id: number): Board{ return this.boardsService.getBoardDetailById(id); } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행

5. READ 3 - 특정 키워드의 게시글을 조회(검색)하는 기능(Query String)

boards.service.ts 특정 keyword의 게시글을 조회하는 비지니스 로직이 추가되었다.
getBoardByAuthor() 메서드는 파라미터로 keyword를 받아서 함수에서 사용된다.
filter() 메서드를 통해서 데이터베이스에 저장된 게시글의 author가 파라미터로 받아온 author와 동일한 경우 해당 게시글들을 board 배열로 조회한다.
조회된 board 배열이 반환된다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 ... // 특정 작성자의 게시글 조회 getBoardByAuthor(author: string): Board[]{ return this.boards.filter((board) => board.author === author) } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
GET 방식 HTTP Method를 받을 수 있는 @Get() 데코레이터를 작성하고 ('/search') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
파라미터 부분에서 @Query(’author’) 를 선언함으로써 Query String을 사용 할 수 있다.
따라서 해당 메서드는 http://localhost:3000/api/boards/search/keyword?author=Sam 과 같은 게시글 작성자를 쿼리 스트링으로 받는 URL의 GET 요청을 처리하게 된다.
/search 추가 경로를 안두고 ‘board?keyword=’처럼 처리하면 일반 조회 ’/board’와 충돌이 있음
메서드 명칭은 getBoardByAuthor()로 지정했다.
메서드에 쿼리 스트링으로 받아온 author 값을 전달
요청에대한 반환(응답)은 boardsServicegetBoardByAuthor(author) 메서드에 경로 변수로 받아온 author 값을 전달하며 호출하여 그 반환 데이터를 응답하게 된다. (→ 결과, 저장된 board[] 배열이 반환 되어 클라이언트로 응답하게 된다.)
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 작성자의 게시글 조회 @Get('/search/:keyword') getBoardByAuthor(@Query('author') author: string): Board[]{ return this.boardsService.getBoardByAuthor(author); } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행

6. DELETE - 특정 게시글을 삭제하는 기능

boards.service.ts 특정 id의 게시글을 삭제하는 비지니스 로직이 추가되었다.
deleteBoardById() 메서드는 파라미터로 id를 받아서 함수에서 사용된다.
filter() 메서드를 통해서 데이터베이스에 저장된 게시글의 id가 파라미터로 받아온 id동일하지 않은 나머지 객체들을 다시 board[] 배열로 할당(저장)한다.
조회된 board 배열이 반환된다.
import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 번호의 게시글 삭제 @Delete('/:id') deleteBoardById(@Param('id') id: number): void{ this.boardsService.deleteBoardById(id); } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
DELETE 방식 HTTP Method를 받을 수 있는 @Delete() 데코레이터를 작성하고 ('/') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
파라미터 부분에서 @Param(’id’) 를 선언함으로써 Path Variable(경로 변수)를 사용 할 수 있다.
따라서 해당 메서드는 http://localhost:3000/api/boards/1 과 같은 게시글 번호를 Path Variable로 받는 URL의 DELETE 요청을 처리하게 된다.
메서드 명칭은 deleteBoardById()로 지정했다.
메서드에 경로 변수로 받아온 id 값을 전달
deleteBoardById(id) 메서드에 경로 변수로 받아온 id 값을 전달하며 호출
import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 번호의 게시글 삭제 @Delete('/:id') deleteBoardById(@Param('id') id: number): void{ this.boardsService.deleteBoardById(id); } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행

7. UPDATE 1 - 특정 게시글을 일부 수정하는 기능(PATCH)

boards.service.ts 특정 id의 게시글의 일부 정보를 수정하는 비지니스 로직이 추가되었다.
updateBoardStatusById() 메서드는 파라미터로 id, @Body()를 통해서 status를 받아서 함수에서 사용된다.
특정 id의 게시글을 찾는 메서드를 재활용하여 getBoardDetailById() 메서드를 통해서 데이터베이스에 저장된 게시글의 id가 파라미터로 받아온 id와 동일한 수정 할 대상인 board 객체를 찾아낸다.
수정 대상 board 객체의 status값을 파라미터로 전달 받은 status값으로 할당(수정)한다.
수정된 board 객체가 반환된다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 ... // 특정 번호의 게시글 조회 getBoardDetailById(id: number): Board { return this.boards.find((board) => board.id == id); } ... // 특정 번호의 게시글의 일부 수정 updateBoardStatusById(id: number, status: BoardStatus): Board { const foundBoard = this.getBoardDetailById(id); foundBoard.status = status; return foundBoard; } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
Patch 방식 HTTP Method를 받을 수 있는 @Patch() 데코레이터를 작성하고 ('/:id/status') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
파라미터 부분에서 @Param(’id’) 를 선언함으로써 Path Variable(경로 변수)를 사용 할 수 있다.
따라서 해당 메서드는 localhost:3000/api/boards/1/status 과 같은 게시글 번호를 Path Variable로 받는 URL의 PATCH 요청을 처리하게 된다.
메서드 명칭은 updateBoardStatusById()로 지정했다.
메서드에 경로 변수로 받아온 id 값을 전달
updateBoardStatusById(id) 메서드에 경로 변수로 받아온 id 값을 전달하며 호출
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; import { BoardStatus } from './board-status.enum'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 번호의 게시글의 일부 수정 @Patch('/:id/status') updateBoardStatusById(@Param('id') id: number, @Body('status') status: BoardStatus): Board { return this.boardsService.updateBoardStatusById(id, status) } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행

8. UPDATE 2 - 특정 게시글을 전체 수정하는 기능(PUT)

boards.service.ts 특정 id의 게시글의 일부 정보를 수정하는 비지니스 로직이 추가되었다.
updateBoardStatus() 메서드는 파라미터로 id, @Body()를 통해서 updateBoardDto를 받아서 함수에서 사용된다.
update-board.dto.ts 생성
import { BoardStatus } from "../board-status.enum"; export class UpdateBoardDto { author: string; title: string; contents: string; status: BoardStatus; }
TypeScript
복사
특정 id의 게시글을 찾는 메서드를 재활용하여 getBoardDetailById() 메서드를 통해서 데이터베이스에 저장된 게시글의 id가 파라미터로 받아온 id와 동일한 수정 할 대상인 board 객체를 찾아낸다.
수정 대상 board 객체의 필드값을 파라미터로 전달 받은 updateBoardDto 객체의 각 필드값으로 할당(수정)한다.
수정된 board 객체가 반환된다.
import { Injectable } from '@nestjs/common'; import { Board } from './board.entity'; import { BoardStatus } from './board-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; import { UpdateBoardDto } from './dto/update-board.dto'; @Injectable() export class BoardsService { private boards: Board[] = []; // 임시 DB처럼 사용할 배열(로컬 메모리) // 저장되는 데이터 타입 Board[] 배열 ... // 특정 번호의 게시글 조회 getBoardDetailById(id: number): Board { return this.boards.find((board) => board.id == id); } ... // 특정 번호의 게시글의 전체 수정 updateBoardById(id, updateBoardDto : UpdateBoardDto): Board { const foundBoard = this.getBoardDetailById(id); const {author, title, contents, status} = updateBoardDto; foundBoard.author = author; foundBoard.title = title; foundBoard.contents = contents; foundBoard.status = status; return board; } }
TypeScript
복사
boards.controller.ts
요청을 받는 컨트롤러 부분이다.
Put 방식 HTTP Method를 받을 수 있는 @Put() 데코레이터를 작성하고 ('/:id') 처럼 해당 메서드의 추가 엔드포인트를 지정한다.
파라미터 부분에서 @Param(’id’) 를 선언함으로써 Path Variable(경로 변수)를 사용 할 수 있다.
@Body()로 DTO 객체를 활용하여 updateBoardDto 를 두번째 파라미터로 받는다.
따라서 해당 메서드는 localhost:3000/api/boards/1 과 같은 게시글 번호를 Path Variable로, 요청 바디의 값들은 DTO 객체로 변환되어 받는 URL의 PUT 요청을 처리하게 된다.
메서드 명칭은 updateBoardById()로 지정했다.
메서드에 경로 변수로 받아온 id 값, 요청 바디의 데이터를 DTO로 변환한 updateBoardDto를 전달
updateBoardStatusById(id, updateBoardDto) 메서드에 경로 변수로 받아온 id, updateBoardDto 객체를 전달하며 호출, 수정된 board 객체를 반환받아 클라이언트로 응답한다.
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './board.entity'; import { CreateBoardDto } from './dto/create-board.dto'; import { BoardStatus } from './board-status.enum'; import { UpdateBoardDto } from './dto/update-board.dto'; @Controller('api/boards') export class BoardsController { // 생성자 주입(DI) constructor(private boardsService: BoardsService){} ... // 특정 번호의 게시글의 전체 수정 @Put('/:id') updateBoardById(@Param('id') id: number, @Body() updateBoardDto: UpdateBoardDto): Board { return this.boardsService.updateBoardById(id, updateBoardDto) } }
TypeScript
복사
POSTMAN을 통한 HTTP 요청 테스트를 진행

9. 3-Layer-Architecture

현재 우리가 작성한 소스코드들이 담겨진 파일들을 살펴보자.
3계층 아키텍처?
애플리케이션을
프레젠테이션 계층 또는 사용자 인터페이스,
데이터가 처리되는 애플리케이션 계층
그리고 애플리케이션과 관련된 데이터가 저장 및 관리되는 데이터 계층
3개의 논리적이고 물리적인 컴퓨팅 계층으로 구성하는 확립된 소프트웨어 애플리케이션 아키텍처
- ibm
Search
 | Main Page | Category |  Tags | About Me | Contact | Portfolio