Nest로 만든 백엔드 서버를 mysql DB와 연결해보자.
Nest 공식 깃허브주소 여기에 sample폴더에는 다양한 샘플코드가 있다. 07 sequelize에서 sequelize를 사용하는 코드를 따라 작성해본다.
git clone https://github.com/nestjs/nest.git
먼저 nest new
명령어를 이용해서 프로젝트를 만들고나면 생성되는 package.json
과 샘플코드에서의 package.json
을 비교해본다.
샘플코드처럼 작성해보기 위해 추가로 필요한 외부모듈들이다.
- @nestjs/sequelize - nest전용 sequelize모듈
- mysql2 - mysql 드라이버
- sequelize - 프로미스 기반 Nodejs ORM
- sequelize-typescript - 선언적 정의를 위한 데코레이터 세트 제공
- @types/sequelize - sequelize에 대한 typescript정의
필요한 모듈들을 설치해준다.
yarn add @nestjs/sequelize mysql2 sequelize sequelize-typescript @types/sequelize
AppModule
에 SequelizeModule
종속성을 주입하자.
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { AppController } from './app.controller';
// import { BoardModule } from './board/board.module';
@Module({
imports: [
SequelizeModule.forRoot({
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '1234',
database: 'nest-board',
models: [],
}),
],
controllers: [AppController],
})
export class AppModule {}
forRoot()
메서드는 Sequelize생성자의 속성들을 모두 지원한다.
그리고 추가로 아래 사진의 속성들도 지원한다.
여기까지 작성했다면, Sequelize객체를 AppModule
루트모듈에 의존성주입했기 때문에, 다른 모듈들에서는 import로 의존성 주입할 필요 없이 바로 가져다 사용할 수 있다.
모델을 정의할 때, 데코레이터를 이용해 선언적인 형태로 작성한다.
아까 설치한 sequelize-typescript
를 패키지를 이용한다.
다양한 데코레이터 사용 법 링크에서 자세히 볼 수 있다.
Advanced Example 데코레이터
각 데코레이터들을 간단하게 살펴본다.
sequelize
의 define options을 모두 사용할 수 있다.
id는 기본클래스에서 상속된다. 기본적으로 INTEGER
타입이고 autoIncrement=true
다. 기본적으로 sequelize에서와 동일하다. @Column({primaryKey: true})를 사용하거나 @PrimaryKey 와 @Column 데코레이터를 같이 사용해서 Override할 수 있다.
sequelize에서는 모델 생성 옵션에서 timestamps : true
로 할 경우 자동으로 createdAt
, updatedAt
을 추가해줬다. Sequelize를 이용해 생성한거나 업데이트 할 때 자동으로 설정되는 필드다.
deletedAt
은 paranoid: true
(timestamps: true 해줘야 함)`할 경우, 생성 됐었다.
아래 사진을 보면 반대로 생각해 볼 수 있다. 어노테이션을 사용할 경우 option이 설정된다.
파라미터 없이 간단히 사용할 수도 있다.
이 경우 타입추론이 가능해야 한다.
타입추론을 사용할 수 없거나 하지 말아야 할 경우에는 아래와 같이 사용한다.
import {DataType} from 'sequelize-typescript';
@Column(DataType.TEXT)
name: string;
@Column({
type: DataType.Float,
comment: "Some value",
...
})
value: number;
아래 사진은 @Column
데코레이터와 함께 사용할 수 있는 데코레이터들이다.
다시 본론으로 돌아가서 Model을 작성해본다.
// board.model.ts
import {
Column,
DataType,
Model,
PrimaryKey,
Table,
} from 'sequelize-typescript';
@Table({ timestamps: true, paranoid: true })
export class Board extends Model<Board> {
@Column
@PrimaryKey
id: number;
@Column
author: string;
@Column(DataType.TEXT)
context: string;
}
모델을 작성했으면 SequelizeModule.forRoot
의 models속성 배열에 넣어 Sequelize가 정상적으로 Model객체를 이용할 수 있게 해준다.
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { AppController } from './app.controller';
import { Board } from './board/board.model';
@Module({
imports: [
SequelizeModule.forRoot({
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '1234',
database: 'nest-board',
models: [Board],
}),
],
controllers: [AppController],
})
export class AppModule {}
그리고 Board스코프 내에서 BoardModel을 사용할 수 있도록 해줘야 한다.
import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import { BoardController } from './board.controller';
import { BoardService } from './board.service';
import { Board } from './board.model';
@Module({
imports: [SequelizeModule.forFeature([Board])],
controllers: [BoardController],
providers: [BoardService],
})
export class BoardModule {}
다음은 서비스에서 Model객체를 직접 사용해보자
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { Board } from './board.model';
@Injectable()
export class BoardService {
constructor(
@InjectModel(Board)
private boardModel: typeof Board,
) {}
async getList(): Promise<Board[]> {
return this.boardModel.findAll();
}
}
이제 서비스에서 DB를 사용할 준비가 끝났다.
SequelizeModule.forRoot()
에서 model속성의 배열에 하드코딩으로 model들을 추가하는 것이 귀찮거나, 애플리케이션 구현 구조가 유출되는게 싫다거나 (import 경로에 의해)한다면 아래 사진처럼 설정한다.
이 옵션을 지정하면 forFeature()
를 통해 등록된 모든 모델이 배열에 자동으로 추가된다.
반대로 forFeature()
를 통해 등록되지 않은 경우 등록되지 않으니 이 옵션을 사용하면 안된다.
@nestjs/sequelize
보다는 @nestjs/typeorm
이 훨씬 더 많이 사용된다.
다음 nestjs 포스팅에서는 typeorm에 대해 자세히 알아봐야겠다.