# Node.js + Express + MySQL + Sequelize example

이 포스팅에서는 Node.js + Express + MySQL + Sequelize를 사용하여 간단한 CRUD를 예시로 알아보겠습니다! 구현 이후에는 postman을 이용하여 직접 호출하는 것 까지 해보겠습니다

# 프로젝트 구조

프로젝트 구조
/src
ㅣㅡ app
ㅣㅡ /config
ㅣㅡㅡ /db.config.js
ㅣㅡ /controllers
ㅣㅡㅡ /tutorial.controller.js
ㅣㅡ /modules
ㅣㅡㅡ /index.js
ㅣㅡㅡ /tutorial.model.js
ㅣㅡ /routes
ㅣㅡㅡ /tutorial.routes.js
ㅣㅡ package.json
ㅣㅡ server.js
  • db.config.js는 MYSQL 연결 및 Sequelize 구성을 위한 설정 파일입니다.
  • server.js는 CORS를 구성하고, Express를 초기화 및 Sequelize 연결, 서버 연결을 담당합니다.
  • models에서는 MYSQL 테이블 구성을 담당합니다.
  • controllers에서는 모든 crud 작업을 처리합니다.
  • routes는 front에서 접근할 경로를 정의합니다.

# 초기 설치

원하는 위치에서 폴더를 만듭니다.

$ mkdir express-mysql-example
$ cd express-mysql-example

package.json 사용을 위해 npm 초기화 합니다. npm init를 입력한 이후 계속 enter 쳐줍니다

프로젝트 진행을 위해 dependencies를 설치합니다

npm install express sequelize mysql2 body-parser cors --save

# express 웹 서버 추가

아래와 같이 코딩 이후 터미널에서 node server.js를 실행하고 localhost:8080에 접속하여 { message: "this is express server" }가 출력되는지 확인합니다

// src/server.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const app = express();

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: true }));

const db = require("./app/models");

db.sequelize.sync();
// 개발 중에는 기존 테이블을 삭제하고 데이터베이스를 다시 동기화해야 할 수 있습니다. force: true다음 코드로 사용
// db.sequelize.sync({ force: true }).then(() => {
//   console.log("Drop and re-sync db.");
// });

require("./app/routes/turorial.routes")(app);

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});
  • Express가 웹서버를 구축합니다
  • body-parser가 request를 구분하고 req.body 객체를 생성합니다.
  • cors는 서버에 연결하고자 하는 front의 주소와 연결을 허용해줍니다.

# MYSQL config 데이터 구성

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "xxxxx", // mysql 초기 설정한 비밀번호
  DB: "test",
  dialect: "mysql",
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
};

처음 5 개의 매개 변수는 MySQL 연결 용입니다. pool선택 사항이며 Sequelize 연결 풀 구성에 사용됩니다.

  • max: 풀의 최대 연결 수
  • min: 풀의 최소 연결 수
  • idle: 연결이 해제되기 전에 유휴 상태 일 수있는 최대 시간 (밀리 초)
  • acquire: 오류가 발생하기 전에 해당 풀이 연결을 시도하는 최대 시간 (밀리 초)

# Sequelize 초기화

// modules/index.js
const dbConfig = require("../config/db.config.js");

const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
  host: dbConfig.HOST,
  dialect: dbConfig.dialect,
  operatorsAliases: false,

  pool: {
    max: dbConfig.pool.max,
    min: dbConfig.pool.min,
    acquire: dbConfig.pool.acquire,
    idle: dbConfig.pool.idle
  }
});

const db = {};

db.Sequelize = Sequelize;
db.sequelize = sequelize;

// routes 사용
db.tutorials = require("./tutorial.model.js")(sequelize, Sequelize);

module.exports = db;

# Sequelize 모델 정의

// modules/tutorial.model.js
module.exports = (sequelize, Sequelize) => {
  const Tutorial = sequelize.define("tutorial", {
    title: {
      type: Sequelize.STRING
    },
    description: {
      type: Sequelize.STRING
    },
    published: {
      type: Sequelize.BOOLEAN
    }
  });

  return Tutorial;
};

# controller 정의

// controllers/tutorial.controller.js
const db = require("../models");
const Tutorial = db.tutorials;
const Op = db.Sequelize.Op;

// Create and Save a new Tutorial
exports.create = (req, res) => {
  // Validate request
  if (!req.body.title) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
    return;
  }

  // Create a Tutorial
  const tutorial = {
    title: req.body.title,
    description: req.body.description,
    published: req.body.published ? req.body.published : false
  };

  // Save Tutorial in the database
  Tutorial.create(tutorial)
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while creating the Tutorial."
      });
    });
};

// Retrieve all Tutorials from the database.
exports.findAll = (req, res) => {
  const title = req.query.title;
  var condition = title ? { title: { [Op.like]: `%${title}%` } } : null;

  Tutorial.findAll({ where: condition })
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving tutorials."
      });
    });
};

// Find a single Tutorial with an id
exports.findOne = (req, res) => {
  const id = req.params.id;

  Tutorial.findByPk(id)
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message: "Error retrieving Tutorial with id=" + id
      });
    });
};

// Update a Tutorial by the id in the request
exports.update = (req, res) => {
  const id = req.params.id;

  Tutorial.update(req.body, {
    where: { id: id }
  })
    .then(num => {
      if (num == 1) {
        res.send({
          message: "Tutorial was updated successfully."
        });
      } else {
        res.send({
          message: `Cannot update Tutorial with id=${id}. Maybe Tutorial was not found or req.body is empty!`
        });
      }
    })
    .catch(err => {
      res.status(500).send({
        message: "Error updating Tutorial with id=" + id
      });
    });
};

// Delete a Tutorial with the specified id in the request
exports.delete = (req, res) => {
  const id = req.params.id;

  Tutorial.destroy({
    where: { id: id }
  })
    .then(num => {
      if (num == 1) {
        res.send({
          message: "Tutorial was deleted successfully!"
        });
      } else {
        res.send({
          message: `Cannot delete Tutorial with id=${id}. Maybe Tutorial was not found!`
        });
      }
    })
    .catch(err => {
      res.status(500).send({
        message: "Could not delete Tutorial with id=" + id
      });
    });
};

// Delete all Tutorials from the database.
exports.deleteAll = (req, res) => {
  Tutorial.destroy({
    where: {},
    truncate: false
  })
    .then(nums => {
      res.send({ message: `${nums} Tutorials were deleted successfully!` });
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while removing all tutorials."
      });
    });
};

// find all published Tutorial
exports.findAllPublished = (req, res) => {
  Tutorial.findAll({ where: { published: true } })
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving tutorials."
      });
    });
};

# routes 정의

// routes/tutorial.routes.js
module.exports = app => {
  const tutorials = require("../controllers/tutorial.controller.js");

  var router = require("express").Router();

  // Create a new Tutorial
  router.post("/", tutorials.create);

  // Retrieve all Tutorials
  router.get("/", tutorials.findAll);

  // Retrieve all published Tutorials
  router.get("/published", tutorials.findAllPublished);

  // Retrieve a single Tutorial with id
  router.get("/:id", tutorials.findOne);

  // Update a Tutorial with id
  router.put("/:id", tutorials.update);

  // Delete a Tutorial with id
  router.delete("/:id", tutorials.delete);

  // Delete all Tutorials
  router.delete("/", tutorials.deleteAll);

  app.use("/api/tutorials", router);
};

# API 테스트

node server.js를 실행하여 서버를 실행합니다.

# post

POST -> `http://localhost:8080/api/tutorials`
body -> {"title": "title 1", "description": "desc 1"}

생성 확인합니다.

# get

GET -> `http://localhost:8080/api/tutorials`

위에서 만든 {"title": "title 1", "description": "desc 1"} 출력 확인합니다.

# 개별 get

GET -> `http://localhost:8080/api/tutorials/1`

위에서 만든 {"title": "title 1", "description": "desc 1"} 출력 확인합니다.

# delete

delete -> `http://localhost:8080/api/tutorials/1`
Last Updated: 3/24/2021, 8:55:12 PM