개발/Node.js

node + postgreSQL + Sequelize

piece5 2023. 9. 20. 23:11

참고)

https://velog.io/@thinkp92/Express-Sequelize-with-PostgreSQL-database%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-Node.js-Restful-CRUD-API-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

https://www.daleseo.com/js-node-es-modules/


Node.js Restful CRUD API 구현하기

※ 참고한 블로그 글은 commonjs로 구현되어 있는데 나는 다른 프로젝트를 ES module로 하였기 때문에 연습을 위해서 바꾸었다.

 

[폴더 구조]

1. node.js 프로젝트 생성

  1. 프로젝트 폴더 만들기
  2. npm init을 하고 package.json 자동 생성하기
  3. package.json에 "type":"module" 추가
  4. postgreSQL과 Express와 Sequelize 관련 모듈 설치하기
npm install express sequelize pg pg-hstore body-parser cors --save

 

2. index.js와 mvc 패턴을 위한 파일 생성

  1. index.js
  2. app/routes/tutorial.routes.js
  3. app/config/db.config.js
  4. app/controllers/tutorial.controller.js
  5. app/models/index.js , app/models/tutorial.model.js

 

3. index.js

  • app.listen위에 app.use를 모두 적어야 한다.
  • db.sequelize.sync()의 위치는 상관은 없어보인다.
import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import db from "./app/models/index.js";
import tutorialRouter from "./app/routes/tutorial.routes.js"

const app = express();
db.sequelize.sync()
  .then(() => {
    console.log("DB Connection successful");
  }).catch((err) => {
    console.error(err);
  })

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

app.use(cors(corOptions));

// parse requests of content-type - application/json
app.use(bodyParser.json());

// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// simple route
app.get("/", (req, res) => {
  res.json({ message: "Welcome to my application." });
});

app.use("/api/tutorials", tutorialRouter);

// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on Port ${PORT}!`);
});

 

4. app/routes/tutorial.routes.js

  • tutorial.controller.js 에서 export를 여러개로 나눠서 작성했기 때문에 import * as [별명] from '~~' 이렇게 작성하여 한번에 불러올 것이다.
import * as express from 'express';
const router = express.Router();
import * as tutorials from "../controllers/tutorial.controller.js";
    
// Create a new Tutorial
router.post("/", tutorials.create);

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

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

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

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

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

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

export default router;

 

5. app/config/db.config.js

  • PostgreSQL Shell 등에서 새로운 DB를 만들고 정보를 아래에 적는다. 
  • dialect는 여러 데이터베이스 (MS-SQL, Oracle, MySQL,PostgreSQL 등) 간에 변경을 용이하게 해준다. 지금은 "postgres"로 설정한다.
export const HOST = ""; // 127.0.0.1
export const USER = ""; // postgres (기본)
export const PASSWORD = "";
export const DB = "";
export const dialect = "postgres"; // *
export const pool = {
	max: 5,
	min: 0,
	acquire: 30000,
	idle: 10000
};

 

6. app/controllers/tutorial.controller.js

  • import db from "../models/index.js"는 export default db;로 db라는 변수에 모아서 내보내기를 했기 때문에 import [별명] from '~~' 로 작성한다. 
  • exports.create --> export function create 로 ES module로 변경 (vscode에서 자동으로 해준다..)
import db from "../models/index.js";
const Tutorial = db.tutorials;
const Op = db.Sequelize.Op;

// Create and save a new tutorial
export function create(req, res) {
  if (!req.body.title) {
    res.status(400).send({
      message: "Content can not be empty!",
    });
    return;
  }

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

  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.
export function findAll(req, res) {
  const title = req.query.title;
  var condition = title ? { title: { [Op.iLike]: `%${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
export function 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
export function 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
const _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,
            });
        });
};
export { _delete as delete };

// Delete all Tutorials from the database.
export function 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 removingall tutorials.",
      });
    });
}

// Find all published Tutorials
export function 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.",
      });
    });
}

 

7. app/models/tutorial.model.js

  • tutorial이라는 테이블 정의하기
export default (sequelize, Sequelize) => {
	const Tutorial = sequelize.define("tutorial", {
		title: {
  			type: Sequelize.STRING
		},
  		description: {
  			type: Sequelize.STRING
		},
        published: {
            type: Sequelize.BOOLEAN
		}
	});

	return Tutorial
};

 

8. app/models/index.js

  • db.config.js 에서 export를 여러개로 나눠서 작성했기 때문에 import * as [별명] from '~~' 이렇게 작성하여 한번에 불러올 것이다.
  • const Sequelize = require('sequelize'); --> import { Sequelize } from 'sequelize';
  • (alias) class Sequelize
    import Sequelize
    This is the main class, the entry point to sequelize. To use it, you just need to import sequelize:
    const Sequelize = require('sequelize');
import * as dbConfig from '../config/db.config.js';
import { Sequelize } from 'sequelize';
import tutorialModel from './tutorial.model.js';

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 = {Sequelize : Sequelize, sequelize : sequelize, tutorials : tutorialModel(sequelize, Sequelize)};

export default db;

 

9. 이제 서버 실행해보기

  • 프로젝트 폴더 경로에서 node index.js 로 서버 실행
  • 서버를 실행하면 만들어둔 데이터베이스에 tutorial table이 생성된다.

 

10. POSTMAN에서 Request해보기

  • 오랜만에 사용해보는데 잘 안돼서 찾아보니 인터넷에서 요청을 보낼 수 없고 desktop app을 설치하여 요청을 보내야한다.
  • 아래처럼 해본다.

  • 성공하면 밑에 이렇게 뜬다.

  • postgres shell에서도 확인해보면 똑같이 뜬다.

 

10. 끝이다.