[20/12/04] - TIL ⎮ ChatterBox Database
12월 04일 (금)
🌻 Today I Learned Database with MySQL
👨🏼💻 ChatterBox Database
🌻 Today I Learned Database with MySQL
이번 스프린트는 Chatterbox Server
가 영속적인 데이터를 가질 수 있도록 만드는 것이다. MySQL
을 통해 나의 로컬 데이터베이스에 데이터들을 저장하고, 서버가 재시작해도 저장된 데이터가 지워지지 않게 해야한다.
1. 스키마 작성
먼저 Chatterbox Server
에 필요한 스키마를 디자인했다. server/schema.sql
파일에서 데이터베이스 테이블의 구조를 정의하고 MySQL
서버에 로드할 CREATE TABLE
문을 작성했다. messages
테이블 구조에는 username
, text
, date
, roomname
이 포함되고, users
테이블 구조에는 username
이 포함되게 작성했다.
schema.sql
DROP DATABASE IF EXISTS chat; // 만약 이미 데이터베이스가 존재하면
CREATE DATABASE chat; // 없애고 새로 만든다
USE chat;
// messages 테이블
CREATE TABLE messages (
id int not NULL PRIMARY KEY AUTO_INCREMENT,
username varchar(255) not NULL,
text text(1024),
date timestamp not NULL DEFAULT CURRENT_TIMESTAMP,
roomname varchar(255) not NULL
);
// users 테이블
CREATE TABLE users (
id int not NULL PRIMARY KEY AUTO_INCREMENT,
username varchar(255) not NULL
);
아래 사진은 mysql -u root -p < server/schema.sql
을 통해 내 MySQL server
에 작성한 schema.sql
을 로드하고 mysql
에서 해당 내용을 확인한 모습이다.
2. 서버
자, 이제 서버를 작성하고 실행해야 한다. 먼저 MySQL
비밀번호를 보안상/편의상 이유로 환경 변수로 분리해놓았다. 아래 터미널 명령을 통해 환경 변수를 설정하고 node.js
상에서 process.env.DATABASE_SPRINT_PASSWORD
라는 변수에서 설정한 값에 접근할 수 있게 했다.
$ export DATABASE_SPRINT_PASSWORD='my_value'
그런데 이렇게 환경 변수를 설정하면 서로 다른 터미널에서는 접근이 안되는 점이 불편했고, dotenv를 사용하면 .env
파일을 통해 접근 가능하게 할 수 있다는 것을 배웠다.
다음으로는 주어진 server/app.js
에서 express
프레임워크를 통한 node.js
서버를 실행시키고, server/db/index.js
에서 mysql npm module
을 사용하여 실행 중인 데이터베이스 서버에 연결한다.
app.js
var express = require('express');
// Middleware
var morgan = require('morgan');
var parser = require('body-parser');
// Router
var router = require('./routes.js');
var app = express();
module.exports.app = app;
// Set what we are listening on.
app.set('port', 3000);
// Logging and parsing
app.use(morgan('dev'));
app.use(parser.json());
// Set up our routes
app.use('/classes', router);
// Serve the client files
app.use(express.static(__dirname + '/../client'));
// If we are being run directly, run the server.
if (!module.parent) {
app.listen(app.get('port'));
console.log('Listening on', app.get('port'));
}
db/index.js
const mysql = require('mysql');
const password = process.env.DATABASE_SPRINT_PASSWORD;
const host = 'localhost';
// user는 root, 패스워드는 위 password 변수
// 실제로 연결할 데이터베이스의 위치(host)는 host 변수
// 데이터베이스 이름(database)은 "chat"
// 데이터베이스 연결을 만들고, 연결 객체 export
module.exports = mysql.createConnection({
host,
user: 'root',
password,
database: 'chat',
});
server/models/index.js
에서는 메시지와 사용자 모델을 정의한다. SQL query
문을 작성하여 실질적인 데이터를 데이터베이스에서 가져와 controller
에게 넘겨주는 역할을 담당한다.
비동기 호출을 구현하기 위해 프로미스 객체를 넘겨주었고 코드는 w3schools.com에 Node.js MySQL을 참고하여 작성했다.
models/index.js
// 위에서 작성한 db/index.js에서 연결 객체를 가져오고
var db = require('../db');
// 연결한다
db.connect((err) => {
if (err) throw err;
console.log('Connected!');
});
module.exports = {
messages: {
// a function which produces all the messages
get: function () {
return new Promise((resolve, reject) => {
db.query('SELECT * FROM messages', function (err, result) {
if (err) reject(err.message);
resolve(result);
});
});
},
// a function which can be used to insert a message into the database
post: function (data) {
return new Promise((resolve, reject) => {
const sql = 'INSERT INTO messages (username, text, roomname) VALUES ?';
const values = [data.username, data.text, data.roomname];
db.query(sql, [[values]], function (err) {
if (err) reject(err.message);
db.query('SELECT * FROM messages', function (err, result) {
if (err) reject(err.message);
resolve(result);
});
});
});
},
},
// users: {...} 생략
};
server/controllers/index.js
는 서버 내에서 클라이언트의 요청에 알맞게 모델 객체 안의 함수를 호출하고, 결과 데이터를 전달하는 역할을 한다.
controllers/index.js
// 위에서 작성한 models/index.js에서 모델 객체를 가져온다
var models = require('../models');
module.exports = {
messages: {
// a function which handles a get request for all messages
get: function (req, res) {
models.messages.get().then((result) => res.send(result));
},
// a function which handles posting a message to the database
post: function (req, res) {
models.messages
.post(req.body)
.then((result) => res.status(201).send(result));
},
},
// users: {...} 생략
};
주어진 server/routes.js
는 요청 URL
에 따라 서버 라우팅 역할을 한다. node.js
웹 서버 코드 app.js
에서 이 파일을 require
하여 라우터로 사용한다.
routes.js
var controller = require('./controllers');
var router = require('express').Router();
//Connect controller methods to their corresponding routes
router.get('/messages', controller.messages.get);
router.post('/messages', controller.messages.post);
router.get('/users', controller.users.get);
router.post('/users', controller.users.post);
module.exports = router;
클라이언트 연결 몇 결과 👍
클라이언트 연결은 기존에 진행했던 Chatterbox client sprint
의 reference
코드를 가져왔고, 현재 스프린트에 client
디렉토리를 만들어 그 안에 담았다. app.js
에서 server URI
를 나의 로컬 MySQL
서버로 바꿔주고, fetch
하는 부분과 render
하는 부분만 살짝 수정했다. 결과 화면이다.
서버를 실행시키고, 클라이언트 페이지를 새로고침하여 메시지 하나를 post
요청하면 MySQL
데이터베이스에 저장되어 나타나는 모습이다.
또한, 서버를 재시작하여도 데이터베이스에 남아있는 데이터를 영속성 있게 가져올 수 있는 모습이다.
느낀 점 🌻
이제는 클라이언트의 HTTP
요청으로 인한 데이터를 서버 컴퓨터의 in-memory
나 node.js
의 fs
모듈을 통한 파일이 아니라 서버와 연결된 데이터베이스에 저장할 수 있다. 데이터베이스에 대해 이해했고, 어떻게 사용하는지와 그 필요성을 인지하긴 했지만 아직 스프린트 코드의 model
, view
, controller
에 대해서는 잘 모르겠다. 어째서 이렇게 나누는 것이고, 왜 필요한 것이고, 이것을 왜 MVC
디자인 패턴이라 부르는 것인가. 다음 스프린트에서 공부하게 될 내용이다. 그래서 이러한 형태의 코드를 데이터베이스 스프린트를 통해 먼저 접하게 한 것 같다.
배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글 달아주시면 수정하겠습니다. 감사합니다 :)
Author And Source
이 문제에 관하여([20/12/04] - TIL ⎮ ChatterBox Database), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@heeseok/201204-TIL-ChatterBox-Database저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)