typescript express sequelize 연결하기

·2021년 11월 29일
1

좌충우돌

목록 보기
26/26

참고: NodeJS Express Typescript로 Sequelize환경구축

위의 블로그 글을 참고하면서 작성했다.

그런데 나는 migrations 이용해서 하는 게 불편해서(그리 큰 규모의 프로젝트도 아니라,,) 그냥 models 디렉토리 안에 모델을 짜고 app.ts에서 sequelize를 sync하는 방식을 채택했다.

사족입니다

그간 담다 프로젝트를 진행하면서 서버를 nodejs + sequelize + js 로 구성했었는데, typescript까지 제대로 다뤄보고 싶어서 공씨 프로젝트를 typescript로 진행하게 되었다.
ts를 각 잡고 공부하진 않았지만 타입을 지정해줘야 한다는 것만 익숙해지니까 그렇게 어렵지는 않았다.

Nest.js 도 있지만 프로젝트 완성까지 남은 시간을 계산해 보고 Nest는 아쉽게도 시도하지 않았다.
언젠간 Nest도 다뤄보고 싶다.

환경

"dependencies": {
"cors": "2.8.5",
"dotenv": "10.0.0",
"express": "4.17.1",
"mysql2": "2.3.3",
"reflect-metadata": "0.1.13",
"sequelize": "6.9.0",
"sequelize-cli": "6.3.0",
"sequelize-typescript": "2.1.1"

},

"devDependencies": {
"@types/cors": "2.8.12",
"@types/express": "4.17.13",
"@types/node": "16.10.3",
"@types/validator": "13.6.6",
"nodemon": "2.0.15",
"ts-node": "10.2.1",
"tsc-watch": "4.5.0",
"typescript": "4.4.3"
}

sequelize 설정하기

src/app.ts
라우터를 아직 설정하지 않은 상태다.

// src/app.ts
import * as dotenv from "dotenv";
import express, { Response, Request, NextFunction } from "express";
import cors from "cors";

import { sequelize } from "./models";
import User from "./models/user.model";

dotenv.config();
// * APP VARIABLES
const PORT: number = parseInt(process.env.PORT as string, 10) || 5000;
const HOST: string = process.env.HOST || "localhost";
const app: express.Application = express();

// * APP CONFIGURATION: middleware
app.use(cors());
app.use(express.json());
app.use((req: Request, res: Response, next: NextFunction) => {
    console.log(`Request occur! ${req.method}, ${req.url}`);
    next();
});

// TODO ROUTER SETTING

// 5000 포트로 서버 실행
app.listen(PORT, HOST, async () => {
    console.log(`server on: listening on ${HOST}:${PORT}`);
    // sequelize-db connection test
    await sequelize
        .sync({ force: true })
        .then(async () => {
            console.log("seq connection success");
        })
        .catch((e) => {
            console.log("seq ERROR: ", e);
        });
});

src/config/config.ts
dotenv를 사용해서 비밀... 들을 관리해줬다.

import * as dotenv from "dotenv";
dotenv.config();
const env = process.env;

export const config = {
    development: {
        username: env.MYSQL_USERNAME || "root",
        password: env.MYSQL_PASSWORD,
        database: env.MYSQL_DATABASE || "gongcdb",
        host: env.MYSQL_HOST || "localhost",
        dialect: "mysql",
        port: env.MYSQL_PORT || "3306",
    },
};

tsconfig.json
이거 안하면 에러 난다.

// ...생략...
"experimentalDecorators": true
// ...생략...

model define해 주기

여기서 에러가 많이 났다.

src/model/user.model.ts**

import {
    Table,
    Column,
    Model,
    AllowNull,
    Unique,
    DataType,
} from "sequelize-typescript";

@Table({ timestamps: false })
export default class User extends Model {
    // id는 자동으로 auto_increment, primarykey 설정된 채로 추가됨.
	  @AllowNull(false)
    @Unique(true)
    @Column(DataType.STRING)
    public email!: string;

    @AllowNull(false)
    @Column(DataType.STRING)
    public password!: string;

    @AllowNull(false)
    @Column(DataType.STRING)
    public nickname!: string;

    @Unique(true)
    @AllowNull(true)
    @Column(DataType.STRING)
    public rasp_token!: string | null;

    @Unique(true)
    @AllowNull(true)
    @Column(DataType.STRING)
    public android_token!: string | null;
}

이때, 제일 중요한 건 @Column 데코레이터를 제일 아래에 둬야 한다는 것!
아래와 같이 @Column 데코레이터를 가장 아래에 안 두고 아무데나 두면 에러가 뜸.

export default class User extends Model {
    @Column(DataType.STRING)
    @AllowNull(false)
    @Unique(true)
    public email!: string;
		// ... 생략
}

// 에러 메시지
// throw new Error(`@Column annotation is missing for "${propertyName}" of class "${target.constructor.name}"` +
//               ^
// Error: @Column annotation is missing for "email" of class "User" or annotation order is wrong.


참고: https://github.com/RobinBuschmann/sequelize-typescript/issues/692

src/model/index.ts

import { Sequelize } from "sequelize-typescript";
import { config } from "../config/config";

export const sequelize = new Sequelize(
    config.development.database,
    config.development.username,
    config.development.password,
    {
        host: config.development.host,
        dialect: "mysql",
        models: [__dirname + "/**/*.model.ts"],
    }
);

실험하기

src/app.ts

// src/app.ts
import * as dotenv from "dotenv";
import express, { Response, Request, NextFunction } from "express";
import cors from "cors";

import { sequelize } from "./models";
import User from "./models/user.model";

dotenv.config();
// * APP VARIABLES
const PORT: number = parseInt(process.env.PORT as string, 10) || 5000;
const HOST: string = process.env.HOST || "localhost";
const app: express.Application = express();

// * APP CONFIGURATION: middleware
app.use(cors());
app.use(express.json());
app.use((req: Request, res: Response, next: NextFunction) => {
    console.log(`Request occur! ${req.method}, ${req.url}`);
    next();
});

// TODO ROUTER SETTING

// get
app.get("/", (req: Request, res: Response) => {
    res.send("hello express");
});

app.get("/test", (req: Request, res: Response) => {
    // email password nickname rasp_token android_token
    const user = new User({
        email: "test@gmail.com",
        password: "1111",
        nickname: "안녕",
    });
	
  
    user.save();
		// 이거 안 쓰면 저장 안됨!

    res.status(200).send({ done: true });

    // res.status(400).send({ done: false });
});

// 5000 포트로 서버 실행
app.listen(PORT, HOST, async () => {
    console.log(`server on: listening on ${HOST}:${PORT}`);
    // sequelize-db connection test
    await sequelize
        .sync({ force: true })
        .then(async () => {
            console.log("seq connection success");
        })
        .catch((e) => {
            console.log("seq ERROR: ", e);
        });
});

그런데 또 에러가 뜬다.
에러: TypeError: Class constructor model cannot be invoked without 'new'

그래서 위 스택오버플로우 답변처럼 tsconfig.json으로 가서 설정을 아래와 같이 바꾸면 아주 잘된다.

tsconfig.json

"target": "ES2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,

참고하기

https://github.com/leejin21/gongC

profile
이것저것 개발하는 것 좋아하지만 서버 개발이 제일 좋더라구요..

0개의 댓글