Nest.js

[Nest.js] Nest.js + PostgreSQL + typeORM CRUD 구현하기 1

Hoo_Dev 2023. 1. 26. 15:39

 

정보 공유보단 메모에 가까운 게시글입니다.
참고만 해주시길 양해 부탁 드립니다 ㅠ.ㅠ

https://www.youtube.com/watch?v=3JminDpCJNE&t=11247s - 따라하면서 배우는 NestJS

 

강의를 참고하여 작성하는 Nest + PostgreSQL + typeORM CRUD 구현

 

우선 DB와 Nest의 연결을 위한 typeorm.config.ts 파일을 configs 폴더 하위에 생성해준다.

import { TypeOrmModuleOptions } from '@nestjs/typeorm';
export const typeORMConfig: TypeOrmModuleOptions = {
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'postgres',
  password: '본인 비밀번호',
  database: '본인 프로젝트 명',
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  synchronize: true,
};

이후 app.module.ts에 자신이 설정한 파일을 import 해준다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardsModule } from './boards/boards.module';
import { typeORMConfig } from './configs/typeorm.config';

@Module({
  imports: [TypeOrmModule.forRoot(typeORMConfig), BoardsModule],
})
export class AppModule {}

우선 게시물 생성 API를 만들기 전, 생성하고자 하는 게시물 폼의 dto, entity, status의 enum을 지정 해 준다.

// src/boards/dto/create-board.dto.ts
import { IsNotEmpty } from 'class-validator';

export class CreateBoardDto {
  @IsNotEmpty()
  title: string;

  @IsNotEmpty()
  description: string;
}

-------------------------------------------------
// src/boards/board.entity.ts
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { BoardStatus } from './board-status.enum';

@Entity()
export class Board extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  description: string;

  @Column()
  status: BoardStatus;
}
--------------------------------------------------
// src/boards/board-status.enum.ts
export enum BoardStatus {
  PUBLIC = 'PUBLIC',
  PRIVATE = 'PRIVATE',
}

dto 지정과 함께 validation 체크 까지 해준다. (설치 방법은 npm install class-validator class-transformer --save)

 

우리는 Repository Pattern을 사용 할 것이다. 해당 패턴에 대한 내용은 기회가 된다면 따로 정리를 해보겠다.

 

해당 패턴을 사용하기 위해 repository 파일을 생성해준다.

import { Injectable } from '@nestjs/common/decorators/core/injectable.decorator';
import { DataSource, Repository } from 'typeorm';
import { BoardStatus } from './board-status.enum';
import { Board } from './board.entity';
import { CreateBoardDto } from './dto/create-board.dto';

@Injectable()
export class BoardRepository extends Repository<Board> {
  constructor(private dataSource: DataSource) {
    super(Board, dataSource.createEntityManager());
  }

  // 서비스와 레포지토리 파일의 분리 (repository pattern)
  async createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
    const { title, description } = createBoardDto;
    const board = this.create({
      title,
      description,
      status: BoardStatus.PUBLIC,
    });

    await this.save(board);
    return board;
  }
}

내가 참고한 영상에서는 typeORM의 버전이 달라 문법적으로 코드가 다를 수 있다.

에러 코드 (TypeError: this.boardRepository.createBoard is not a function)

 

내가 참고 한 방법은 아래 스택오버플로우의 글을 보고 참고하여 작성했다.

- https://stackoverflow.com/questions/72549668/how-to-do-custom-repository-using-typeorm-mongodb-in-nestjs

 

How to do custom repository using TypeORM (MongoDB) in NestJS?

I have a question. With @EntityRepository decorator being marked as deprecated in typeorm@^0.3.6, what is now the recommended or TypeScript-friendly way to create a custom repository for an entity in

stackoverflow.com

이후 service 코드를 보자

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Board } from './board.entity';
import { BoardRepository } from './board.repository';
import { CreateBoardDto } from './dto/create-board.dto';

@Injectable()
export class BoardsService {
  constructor(
    @InjectRepository(Board)
    private boardRepository: BoardRepository,
  ) {}

  createBoard(createBoardDto: CreateBoardDto): Promise<Board> {
    return this.boardRepository.createBoard(createBoardDto);
  }

  getBoardById(id: number): Promise<Board> {
    return this.boardRepository.getBoardById(id);
  }
}

repository pattern 을 적용하여 가독성이 좋은 service 코드를 볼 수 있다.

 

controller

import {
  Body,
  Controller,
  Get,
  Param,
  Post,
  UsePipes,
  ValidationPipe,
} from '@nestjs/common';
import { Board } from './board.entity';
import { BoardsService } from './boards.service';
import { CreateBoardDto } from './dto/create-board.dto';

@Controller('boards')
export class BoardsController {
  constructor(private boardsService: BoardsService) {}

  @Post()
  @UsePipes(ValidationPipe)
  createBoard(@Body() createBoardDto: CreateBoardDto): Promise<Board> {
    return this.boardsService.createBoard(createBoardDto);
  }

  @Get('/:id')
  getBoardById(@Param('id') id: number): Promise<Board> {
    return this.boardsService.getBoardById(id);
  }
}

controller에선 api의 요청 주소를 작성해주고 필요한 params, body, data 등 컨트롤 해줄 수 있다.

 

Learnd

1. Validation Check

2. Repository Pattern

3. 컨트롤러 - 서비스 - 레포지토리 사이에서의 객체지향적인 코드 작성

4. typeORM, postgreSQL 사용법

 

아직은 백엔드 지식과 객체지향적인 개념이 부족해서 정보 공유 성격의 게시글은 포스팅하지 못했다. 이후 더 공부해서 남들에게도 설명을 쉽고 유연하게 할 수 있도록 노력하자.