Express 개발 강좌, PostgreSQL과 Sequelize를 이용한 관계형 데이터베이스 연동

1. 서론

Node.js는 비동기 프로그래밍을 지원하는 서버 사이드 플랫폼으로, 그 중 Express.js는 간결하고 강력한 웹 애플리케이션 프레임워크로 널리 사용됩니다. 본 강좌에서는 PostgreSQL 데이터베이스와 ORM(Object Relational Mapping) 라이브러리인 Sequelize를 활용하여 Express 애플리케이션에 관계형 데이터베이스를 연결하는 방법에 대해 자세히 알아보겠습니다.

2. 환경 설정

우선, 프로젝트를 위해 Node.js 및 PostgreSQL이 설치되어 있어야 합니다. PostgreSQL 설치 후 데이터베이스를 생성하고 다음 단계를 진행합니다.

2.1. Node.js 프로젝트 생성

mkdir express-postgresql-example
cd express-postgresql-example
npm init -y

2.2. 필요한 패키지 설치

Express, Sequelize, pg (PostgreSQL 드라이버), 관련 패키지를 설치합니다.

npm install express sequelize pg pg-hstore

3. PostgreSQL 데이터베이스 설정

PostgreSQL 데이터베이스에 접속하여 아래와 같이 데이터베이스를 생성합니다.
명령줄에서 psql을 실행한 후 다음 SQL 명령어를 입력합니다.

CREATE DATABASE example_db;

테이블 구조를 다음과 같이 설정하겠습니다.

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100) UNIQUE
);

3.1. Sequelize 모델 생성

Sequelize를 통해 위의 users 테이블에 대한 모델을 생성합니다.

4. Express 서버 설정

이제 Express 서버를 설정해 보겠습니다. server.js 파일을 만들어 주십시오.

const express = require('express');
const { Sequelize, DataTypes } = require('sequelize');

// 서버 및 데이터베이스 설정
const app = express();
const sequelize = new Sequelize('example_db', 'username', 'password', {
    host: 'localhost',
    dialect: 'postgres'
});

// 모델 정의
const User = sequelize.define('User', {
    name: {
        type: DataTypes.STRING,
        allowNull: false
    },
    email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true
    }
}, {
    tableName: 'users'
});

// 미들웨어
app.use(express.json());

// RESTful API 구현
app.get('/users', async (req, res) => {
    const users = await User.findAll();
    res.json(users);
});

app.post('/users', async (req, res) => {
    const { name, email } = req.body;
    const user = await User.create({ name, email });
    res.status(201).json(user);
});

// 서버 시작
const PORT = process.env.PORT || 3000;
app.listen(PORT, async () => {
    try {
        await sequelize.authenticate();
        console.log('Database connected');
        console.log(`Server is running on http://localhost:${PORT}`);
    } catch (error) {
        console.error('Unable to connect to the database:', error);
    }
});

5. 데이터 CRUD 작업

5.1. Create (생성)

POST /users 엔드포인트를 통해 사용자를 생성할 수 있습니다. 요청 본문에 사용자 이름과 이메일을 포함해야 합니다.

5.2. Read (조회)

GET /users 엔드포인트를 호출하면 데이터베이스에 있는 모든 사용자가 반환됩니다.

5.3. Update (수정)

app.put('/users/:id', async (req, res) => {
    const { id } = req.params;
    const { name, email } = req.body;
    const user = await User.findByPk(id);
    if (user) {
        user.name = name;
        user.email = email;
        await user.save();
        res.json(user);
    } else {
        res.status(404).json({ message: 'User not found' });
    }
});

5.4. Delete (삭제)

app.delete('/users/:id', async (req, res) => {
    const { id } = req.params;
    const user = await User.destroy({ where: { id } });
    if (user) {
        res.status(204).send();
    } else {
        res.status(404).json({ message: 'User not found' });
    }
});

6. Sequelize 응용: 관계 설정

Sequelize는 모델 간의 관계를 설정할 수 있습니다. 예를 들어, 사용자가 여러 게시글을 작성하는 구조로 만들기 위해 Post 모델을 추가해 보겠습니다.

const Post = sequelize.define('Post', {
    title: {
        type: DataTypes.STRING,
        allowNull: false
    },
    content: {
        type: DataTypes.TEXT,
        allowNull: false
    }
}, {
    tableName: 'posts'
});

// 관계 설정
User.hasMany(Post);
Post.belongsTo(User);

이제 사용자는 여러 게시글을 가질 수 있으며, 게시글은 하나의 사용자에게 속합니다.

7. 데이터베이스 마이그레이션

Sequelize CLI를 사용하여 데이터베이스를 마이그레이션할 수 있습니다. 먼저, sequelize-cli 패키지를 설치합니다.

npm install --save-dev sequelize-cli

그리고 다음 명령어로 마이그레이션을 생성합니다.

npx sequelize-cli migration:generate --name create-users

마이그레이션 파일 작성

생성된 파일에 다음 내용을 추가합니다.

module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface.createTable('users', {
            id: {
                type: Sequelize.INTEGER,
                autoIncrement: true,
                primaryKey: true
            },
            name: {
                type: Sequelize.STRING,
                allowNull: false
            },
            email: {
                type: Sequelize.STRING,
                allowNull: false,
                unique: true
            },
            createdAt: {
                allowNull: false,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: false,
                type: Sequelize.DATE
            }
        });
    },
    down: async (queryInterface, Sequelize) => {
        await queryInterface.dropTable('users');
    }
};

마이그레이션을 실행하여 테이블을 생성합니다.

npx sequelize-cli db:migrate

8. 성능 최적화

데이터베이스와의 연결을 최적화하고, 필요한 경우 인덱스를 추가하여 쿼리 성능을 개선할 수 있습니다. Sequelize는 쿼리 최적화를 위한 다양한 옵션을 제공합니다.

User.findAll({
    where: { email: { [Op.like]: '%@gmail.com%' } },
    order: [['createdAt', 'DESC']],
    limit: 10
});

9. 결론

본 강좌를 통해 Express.js와 PostgreSQL, Sequelize를 이용한 웹 서버의 기본적인 구조와 데이터베이스 연동 방법을 익혔습니다. 이와 같은 구성을 통해 RESTful API를 효율적으로 구축할 수 있으며, 데이터베이스와 상호작용하는 강력한 기능을 활용할 수 있습니다.