[Node.js] Spring to Node : Model & Sequelize

E woo·2024년 7월 11일

Node.js

목록 보기
3/4
post-thumbnail

Model

가장 먼저 데이터베이스 스키마와 관련된 모델을 정의해보자!

하지만 그전에! 일단 MySQL DB 와 연결부터 해야지..

npm install mysql
var mysql = require('mysql');

var db_info = mysql.createConnection({
  host     : 'localhost',
  port     : '3306',
  user     : 'root',
  password : '1234',
  database : 'flow'
});
 
module.exports = {
    init: function () {
      return mysql.createConnection(db_info);
    },
    connect: function (conn) {
      conn.connect(function (err) {
        if (err) console.error("mysql connection error : " + err);
        else console.log("mysql is connected successfully!");
      });
    },
  };

config 폴더의 db.js 파일로 db 정보와 이후 connection 을 만들기 위해
init 과 connect 모듈 형식으로 내보낸다.

이렇게 connect 를 통해 직접 쿼리를 날리는 등의 작업이 가능하지만!
우리는 직접 쿼리를 날리는 방식이 아닌 ORM 을 이용해 모델을 정의하고,
이에 따라 제공되는 함수 (Spring Boot JPA 처럼) 를 이용하면서 객체지향 패러다임을

활용할 것이기 때문에 위의 직접 DB 연결 대신!!
Node.js 의 대표적인 ORM 인 Sequelize 를 사용할 것이다!

Sequelize

npm i sequelize sequelize-cli

우선 패키지를 설치해주고

npx init sequelize

를 통해 Sequelize 를 초기화할 경우

이런 폴더와 파일들이 생긴다고 한다!

config/config.json 을 통해 db.js 로 MySQL 데이터베이스와의 연결 정보 그대로 입력해준다.

{
  "development": {
    "username": "root",
    "password": "1234",
    "database": "sys",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

우선은 따로 Test 나 Production 은 진행하지 않을 예정이니 Development 부분만 설정한다.

만약 데이터베이스가 없다면

npx sequelize db:create

로 생성할 수 있다지만 이미

데이터베이스와 테이블이 존재하므로 생성없이 진행한다!

  • mysql2 설치

Sequelize 사용을 위해선 mysql 가 아닌 mysql2를 설치해야 한다!

Model 생성

드디어 모델 생성이다!

npx sequelize model:generate --name Extensions --attributes extension:string,type:string,is_checked:boolean

sequelize-cli 를 이용해 이름과 속성을 정의한다.

MySQL 과 Sequelize 자료형 비교
[ORM] 📚 시퀄라이즈 - 모델(테이블) 정의하기

그러면 다음과 같이 models 폴더에 extensions.js 파일이 생성된다.

  • extensions.js
'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class Extensions extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
    }
  }
  Extensions.init({
    extension: DataTypes.STRING,
    type: DataTypes.STRING,
    is_checked: DataTypes.BOOLEAN
  }, {
    sequelize,
    modelName: 'Extensions',
  });
  return Extensions;
};

Spring 의 Entity 와 비교했을때, 어노테이션으로 깔끔하게 정의된 속성들 때문에
가독성면에서는 Spring 이 더 좋은 것 같고,

대신 Node.js 에서는 sequelize-cli 로
명령어를 통해 바로 모델을 만들 수 있다는 점에선 더 간편하기도 한 거 같다!
이때 migrations 폴더에는 데이터베이스의 스키마 변경을 추적하는 파일이 생기기 떄문에

다음과 같이 파일이 생성되고, 내가 따로 속성 정의하지 않은 id와 createAt, updateAt 이
같이 생성되는 것을 볼 수 있다. 근데 나는 필요 없으니 지우자!

그럼 이제 제대로 Model 이 정의되어 DB 에 반영되는지 테스트 해보자!

const models = require("./src/models");

models.Extensions.create({
    extension: ".pdf",
    type: "fix",
    is_checked: false
  }).then(() => console.log("Data is created!"));

될 줄 알았으나...

  • timestamps : false

근데 나는 필요 없으니 createAt 과 updateAt 을 지웠는데도

계속 해당 값을 자동으로 들어간다…

model 에서 이 둘의 컬럼을 자동으로 생성하는 timestamps 옵션이 default 로 켜져있다고 한다.
따라서 이를 Model 정의에서 false 로 바꿔줘야 한다!

다시 실행해보면 정상적으로 연결되어 삽입된다!!!!

그 외 이모저모

결론 : 여기서는 일단 DTO, Repository 는 구현 X !!

DTO

Spring 에서도 DTO 를 정의했었고, Python 에서는 Model 을 JSON 포맷으로 변환하기 위해
Serializer 를 지원했지만 Node.js 는 JS 기반이기 때문에 따로 타입 선언이 없으며
이러한 특성 때문인지 따로 제공하는 DTO 를 위한 패키지나 형식이 잘 없는 듯 하다..

(TypeScript 를 쓰는 Next.js 의 예시에는 DTO 를 사용하는 예제가 꽤 보이지만..)

사실 Spring 에서도 JPA 로 받은 Entity 객체를 그대로 ResponseEntity 에 담아 보낼 수도
있었지만 이후 상황에 따른 API 응답 정보가 다를 수 있고, Entity 는 ORM 을 통해 DB 와 연결된

객체이기 때문에 이를 그대로 사용하는 것은 의존적일 수 있다..!
(라고는 해도 실제로 지금 Spring 프로젝트에서 구현한 DTO 와 Entity 는 거의 같다..)

라는 명목하에 썼던 것이기 때문에

이번 Node.js 에서도 따로 JS 파일을 만들고
모듈로 내보내 사용할 수 있지만 이번에는 그냥 바로 Model 반환 값을 사용하고,
이후 Tyesscript 와 Next.js 를 사용할 때 한번 구현해보자!

p.s. Next.js 에서는 DTO 에 데코레이터를 통해 유효성 검증까지 쉽게 할 수 있다고 한다..

Repository

Node.js 에서 Repository 를 따로 분리하여 구현하는 경우도 찾아보면 사례나 예시가
흔하지는 않은데 그 이유는 대충 이런 느낌일 것 같다

Sequelize는 Spring Data JPA 처럼 따로 인터페이스를 통한 메서드 정의가 필요없다.

Spring Data JPA 에서 제공하는 ORM 으로 DML 을 구현하기 위해서는 특정 메서드 작명에
맟춰서 이를 정의하여 사용할 수 있다. ex) Extension findByExtension(String extension);

그러나 Sequelize 에서는 특정 메서드의 인자 값을 이용해 DML 을 수행하므로
기본적으로 별도의 파일 구성은 필요하지 않다.

만약 서비스가 커지고 DB 테이블의 관계가 복잡해지며, N + 1 이라던지 특정 Query 를
커스텀해서 사용해야 하는 경우가 빈번하다면 이를 따로 Repository 로 분리할 수 있겠지만
지금 구조는 그렇게 복잡하지 않으며 아주 단순한 DML 을 사용하므로 굳이 Repository

까지 분리해서 구현할 필요는 없어보인다..!

그럼 이제 Controller 와 Service 에 대한 부분을 구현해보자!


  • 참고자료

[Node.js] Sequelize 다루기 - 배하람의 블로그

Nodejs: Sequelize를 이용한 사용자 모델 생성

profile
뒘벼

0개의 댓글