NestJS + postgres + typeorm 연동하기 (서버 DB 연결)
BE/NestJS2023. 11. 21. 00:09NestJS와 postgres, typeorm을 연동하기 위한 방법을 소개합니다. 연동하기 전에 postgres을 먼저 실행해줍니다.
postgres 실행
꼭 도커를 띄울 필요는 없지만, docker로 띄우는것이 편해서 본 글에서는 docker로 postgres를 띄우고 연동하는 방법에 대해 소개합니다. 도커로 띄우는 방법은 아래 글 참고바랍니다.
의존성 설치
postgres를 사용하기 위해, 프로젝트에 pg 라이브러리를 추가합니다.
yarn add pg
typeorm과 nestjs에서 typeorm을 사용할 수 있게 해주는 @nestjs/typeorm을 설치합니다.
yarn add typeorm @nestjs/typeorm
typeorm config 설정
src/configs/typeorm.config.ts
를 생성합니다.
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
export const typeOrmModuleOptions: TypeOrmModuleOptions = {
type: 'postgres', // postgres db를 명시
host: 'localhost', // postgres host
port: 5432, // postgres port
username: 'postgres', // db username
password: 'root', // db password
database: 'secondhand-trade-db', // database name
entities: [__dirname + '/../**/*.entity.{js,ts}'], // entity class를 기반으로 테이블을 생성할 수 있도록 entity 파일 규칙 정의
synchronize: true,
};
설정된 config를 app.module.ts
에 @Module
데코레이터의 imports 부분에 추가합니다. 추가를 할때는 @nestjs/typeorm
의 TypeOrmModule.forRoot()
를 사용합니다.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BoardsModule } from './boards/boards.module';
import { typeOrmModuleOptions } from './configs/typeorm.config';
@Module({
imports: [TypeOrmModule.forRoot(typeOrmModuleOptions), BoardsModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Entity 생성
위에서 NestJS, typeorm, postgres를 모두 연결했습니다. 이제 Entity를 생성해서 db 테이블을 생성해보도록 하겠습니다. boards entity를 생성해보겠습니다.
우선 src/boards/boards.entity.ts를 생성합니다. 그리고 아래와 같이 class를 작성합니다.
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { BoardStatus } from './boards.model';
@Entity()
export class Boards extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
description: string;
@Column()
status: BoardStatus;
}
@Entity()
: 해당 클래스가 엔티티라는 것을 명시할때 사용@PrimaryGeneratedColumn()
: 해당 컬럼이 해당 테이블의 primary key를 명시할 때 사용@Column()
: 일반 컬럼을 명시할때 사용
왜 typeorm을 사용하는가?
typeorm과 같이 ORM을 사용하지 않으면 직접 DB 쿼리를 작성해서 테이블을 생성해야합니다. 예를들어, CREATE TABLE boards ( id INTEGER AUTO_INCREAMENT PRIMARY KEY, ...생략...) 와 같이 작성할 수 있습니다. typeorm을 사용하게 되면 DB 쿼리 작성없이 코드단에서 테이블을 관리할 수 있기 때문에 유지보수하기도 편리합니다.
요약하면 orm은 객체와 관계형 데이터베이스의 데이터를 자동으로 연결 및 조작해준다고 생각하면 됩니다.
이제 nestjs 서버를 실행해보면, 자동으로 테이블이 만들어지는 것을 확인할 수 있습니다.
yarn start:dev
Repository 생성
Entity는 테이블을 생성하기 위해 만들었다면, Repository는 데이터베이스에 CRUD 작업을 하기 위해 생성합니다.
src/boards/boards.repository.ts를 생성하고 아래와 같이 작성합니다.
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Boards } from './boards.entity';
@Injectable()
export class BoardsRepository extends Repository<Boards> {}
그리고, 다른 곳에서 사용할 수 있도록 Boards 엔티티를 BoardsModule의 imports에 추가하고, BoardsRepository를 provider에 추가합니다. 엔티티를 추가를 할때는 TypeOrmModule.forFeature()
메소드를 사용합니다.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { BoardsController } from './boards.controller';
import { BoardsService } from './boards.service';
import { Boards } from './boards.entity';
import { BoardsRepository } from './boards.repository';
@Module({
imports: [TypeOrmModule.forFeature([Boards])], // entity 추가
controllers: [BoardsController],
providers: [BoardsService, BoardsRepository], // Repository를 provider에 추가
})
export class BoardsModule {}
이제 서비스에서 repository를 사용할 수 있도록 의존성 주입을 합니다. 주입을 할때는 @InjectRepository
데코레이터를 사용합니다.
// boards.service.ts
@Injectable()
export class BoardsService {
constructor(
@InjectRepository(Boards)
private boardsRepository: BoardsRepository,
) {}
}
create() 메소드를 통해, 게시글을 삽입하는 메소드를 추가합니다. create()이후 save()를 해줘야 database에 반영이 됩니다.
@Injectable()
export class BoardsService {
// ... 생략 ...
/**
* 게시글을 생성하는 API
* @param createBoardDto
*/
async createBoard(createBoardDto: CreateBoardDto) {
const { title, description } = createBoardDto;
const board = this.boardsRepository.create({
title,
description,
status: BoardStatus.PUBLIC,
});
await this.boardsRepository.save(board);
return board;
}
}
그리고, typeorm의 find()와 findOne() 메소드로 게시글을 가지고 올 수 있는 메소드를 추가합니다.
@Injectable()
export class BoardsService {
// ... 생략 ...
/**
* 전체 게시글을 가지고 오는 API
*/
getAllBoards() {
return this.boardsRepository.find();
}
/**
* 특정 게시글을 가지고 오는 API
* @param id
*/
async getBoardById(id: number): Promise<Boards> {
const board = await this.boardsRepository.findOne({ where: { id } });
if (!board) throw new NotFoundException(`Can't found board. id: ${id}`);
return board;
}
}
서비스 로직을 다 작성했으니 controller를 생성합니다.
import {
Body,
Controller,
Get,
Param,
ParseIntPipe,
ParseUUIDPipe,
Post,
} from '@nestjs/common';
import { BoardsService } from './boards.service';
import { CreateBoardDto } from './dto/create-board.dto';
@Controller({ path: 'boards' })
export class BoardsController {
constructor(private boardsService: BoardsService) {}
@Get('/')
getAllBoards() {
return this.boardsService.getAllBoards();
}
@Get('/:id')
getBoard(@Param('id', ParseIntPipe) id: number) {
return this.boardsService.getBoardById(id);
}
@Post('/')
createBoard(@Body() createBoardDto: CreateBoardDto) {
return this.boardsService.createBoard(createBoardDto);
}
}
postman 또는 curl을 통해 데이터가 잘 생성되는지 확인해봅니다.
'BE > NestJS' 카테고리의 다른 글
typeorm remove()와 delete() 차이 (NestJS) (0) | 2023.11.21 |
---|---|
NestJS Pipe를 이용하여 데이터 변환 및 검증 (1) | 2023.11.20 |
NestJS에서 서비스(Service) 개념 및 서비스 생성하기 (0) | 2023.11.19 |
NestJS 컨트롤러(Controller) 개념 및 정의하기 (0) | 2023.11.17 |
NestJS의 모듈(module) 개념 및 module 정의하기 (0) | 2023.11.17 |
IT 기술에 대한 글을 주로 작성하고, 일상 내용, 맛집/숙박/제품 리뷰 등 여러가지 주제를작성하는 블로그입니다. 티스토리 커스텀 스킨도 개발하고 있으니 관심있으신분은 Berry Skin을 검색바랍니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!