프론트엔드에서 문의하기 부분의 다음 코드로 기본적인 데이터 요청을 테스트하고자 한다.
contact.ejs
<%-include('layouts/header.ejs')%>
<h2>문의하기</h2>
<form action="/api/contact" method="post">
<ul>
<li>이름 : <input type="text" name="name" required></li>
<li>연락처 : <input type="text" name="phone" required></li>
<li>이메일 : <input type="text" name="email" required></li>
<li>내용 : <br>
<textarea name="memo" cols="50" rows="10"></textarea>
</li>
<button type="submit">문의하기</button>
</ul>
</form>
<%-include('layouts/footer.ejs')%>
Frontend 커밋 이후 → master 체크아웃 → 현재까지 변동사항 master로 병합 ( git merge Frontend)
또는 GUI로 Merge
Frontend 커밋 이후 → master 체크아웃 → 현재까지 변동사항 master로 병합 (git merge Frontend)
app.js에서 위 form의 요청을 받고 응답을 보낼 라우터를 아래와 같이 작성하고 서버를 실행해둔다.
app.post('/api/contact', (req, res) => {
const name = req.body.name;
const phone = req.body.phone;
const email = req.body.email;
const memo = req.body.memo;
const data = `${name} ${phone} ${email} ${memo}`
res.send(data);
})
위 작성된 문의하기 폼을 통해서 각 필드값들을 form을 통해 post 요청할 수 있다.
특히 단순한 조회 이외 작성, 수정, 삭제 등은 POST요청으로 해야 Payload에 데이터를 은닉하여 전송 할 수 있다. get요청과 다르게 request의 body에서 데이터를 보내게 된다. 하지만 애초에 body.name 자체를 읽어내지 못하게 된다.
또는, 아래와 같이 나타난다.
이때 다음과 같이 데이터가 비정상적으로 읽히게 된다. Express.js는 기본적으로 요청의 본문을 파싱해주지 않기 때문에 body-parser를 사용하면 쉽게 요청 데이터에 접근할 수 있다.
https://www.npmjs.com/package/body-parser
body-parser
Node.js body parsing middleware. Latest version: 1.20.3, last published: 4 months ago. Start using body-parser in your project by running `npm i body-parser`. There are 26332 other projects in the npm registry using body-parser.
www.npmjs.com
npm install body-parser
Express앱 상단에 body-parser를 사용할 수 있도록 선언해야 한다. 공식문서에는 아래 그림처럼 어플리케이션에서 body-parser를 적용 시키도록 안내되어 있다.
위 코드를 참고하여 프로젝트에 아래와 같이 코드를 적용했다.
const express = require('express')
const ejs = require('ejs')
const bodyParser = require('body-parser')
const app = express()
const port = 3000
app.set('view engine', 'ejs');
app.set('views', './views')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse JSON
app.use(bodyParser.json())
이후 인풋필드에 데이터들을 입력하고 요청을 하면 response로 data에 할당한 변수들이 정상적으로 출력되는 것을 확인할 수 있다.
로컬 환경의 MySQL 데이터베이스를 구축하고 프로젝트와 연결하고자 한다.
데이터베이스 GUI툴은 MySQL-Workbench 를 포함하여 수 없이 많이 있지만 DBeaver 또한 직관적이고 라이트하여 사용하기 편리하다.
데이터베이스 생성 이후 우선 CLI환경에서도 익숙해지는것도 필요하기 때문에 간단한 CLI로 진행하고자 한다.
우선 위 MySQL 로컬 데이터베이스 설치 및 실행이 완료되면 아래 과정을 진행한다.
express에서 mysql과 연결하기 위해서는 mysql2 미들웨어를 설치해야 한다.
https://www.npmjs.com/package/mysql2
mysql2
fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS. Latest version: 3.12.0, last published: a month ago. Start using mysql2 in your project by running `npm i mysql2`. There are 5114 other projects in the npm
www.npmjs.com
npm install myspl2
mysql2를 설치하면 app.js에서 mysql을 사용할 수 있도록 설정해주어야 한다.
const express = require('express')
const ejs = require('ejs')
const bodyParser = require('body-parser')
const mysql = require('mysql2');
const app = express()
const port = 3000
...
// MySQL connection
const connection = mysql.createConnection({
host: "localhost",
user: "inyongkim",
password: "1234",
port: 3306,
database: "nodejs_sample",
insecureAuth: true,
});
하지만 현재 app.js에서는 host, user, password 등 민감함 일부 사용자 정보 등이 담기게 될 수 있고 github 등 원격 저장소를 통해서 공개되어 알수 없는 사고가 발생할 수 있다. 따라서 이런 민감한 정보들은 별도로 관리하고 참조하는 방법을 사용하는 것이 좋다.
dotenv는 Node.js 애플리케이션에서 환경 변수를 로드하는 데 사용되는 미들웨어이다. 애플리케이션의 설정 정보, 비밀 키, API토큰 등과 같은 중요한 데이터를 안전하게 저장하는 데 사용된다. DB 접속 정도 또한 사용자 계정, 비밀번호가 담기기 때문에 이를 활용하여 관리하는 것이 좋다.
npm instlal dotenv
아래처럼 각 정보들을 직접 입력해둔다.
app.js에서 해당 파일이 환경 변수가 담긴 것을 인식해야하고 로드할 수 있어야한다. 다음과 같이 설정 파일임을 서언한다.
require('dotenv').config();
이후 app.js의 mysql 커넥션 코드는 다음처럼 변수명으로 대체하여 은닉할 수 있다.
// MySQL connection
const connection = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PW,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
insecureAuth: true,
});
하지만 아직 .env 파일 자체가 git 버전관리 파일에 포함되어 있으며 이것이 github로 전송되어 내용이 공개되게 된다. gitignore에 .env 파일을 추적 제외하여 업로드할 수 없도록 한다.
이제 mysql2 미들웨어를 통해 어플리케이션은 mysql 데이터베이스와 연결되도록 설정되었다. 이제 mysql 데이터베이스에 테이블을 생성하여 작동을 확인해야 한다.
터미널을 통해서 mysql에 접근한다.
myql -u {username} -p
보통 DB계정이름은 root으로 되어있을 수 있으며 타 계정을 사용하는 경우 grant를 통해 테이블등 생성 권한, 접근 권한 등을 설정해주어야 한다.
show database;
데이터베이스 목록을 조회한다. 기본적으로 처음 설치해도 기본 샘플 데이터베이스들이 보여진다.
create database {dbname};
원하는 이름의 데이터베이스를 생성한다. 그리고 다시 show databases; 로 조회하면 아래처럼 원하는 데이터베이스가 생성된 것을 확인 할 수 있다.
간단한 테이블을 생성하고자 한다. MySQL은 RDBMS로 스키마에 따라 데이터가 존재하게 되는데,
스키마란 테이블의 구조, 타입, 제약조건 등 정해진 틀, 설정이라고 생각하면 된다.
따라서 DB생성자는 이런 구조를 정확하게 먼저 생성해주게 되어 있으며 데이터는 그 스키마에 맞는 데이터들이 삽입되게 된다.
아래처럼 contact라는 테이블의 구조를 상세히 적어서 생성해준다.
CREATE TABLE IF NOT EXISTS contact (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
phone VARCHAR(20),
email VARCHAR(255),
memo TEXT,
create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
modify_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
이후 show tables;로 생성된 테이블을 살펴 볼 수 있다.
설정한 타입 및 제약조건등을 확인하기 위해서는 아래 명령어로 살펴 볼 수 있다.
DESC contact;
mysql 데이터베이스에 원하는 규격의 테이블이 생성되었으며, app.js에서는 mysql2 미들웨어로 커넥션을 구성하였다. 이제 app.post() 요청에서 정상적으로 데이터가 삽입되는지 확인해야 한다.
app.js의 전체적인 코드는 다음과 같다.
const express = require('express')
const ejs = require('ejs')
const bodyParser = require('body-parser')
const mysql = require('mysql2');
require('dotenv').config();
const app = express()
const port = 3000
app.set('view engine', 'ejs');
app.set('views', './views')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse JSON
app.use(bodyParser.json())
// MySQL connection
const connection = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PW,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
insecureAuth: true,
});
...
app.post('/api/contact', (req, res) => {
const name = req.body.name;
const phone = req.body.phone;
const email = req.body.email;
const memo = req.body.memo;
const SQL_Query = `INSERT INTO contact(name, phone, email, memo, create_at, modify_at) VALUES ('${name}','${phone}','${email}','${memo}',NOW(), NOW())`;
connection.query(SQL_Query, (err, result) => {
if (err) {
console.error('데이터 삽입 중 에러 발생:', err);
res.status(500).send('내부 서버 오류');
} else {
console.log('데이터가 삽입되었습니다.');
res.send("<script>alert('문의사항이 등록되었습니다.'); location.href='/'</script>");
}
});
});
contact 페이지에서 입력한 값들이 정상적으로 전송 되고 데이터베이스에도 INSERT문이 작동되어 저장된 것을 확인 할 수 있다.
select * from contact;
위 mysql 연결은 현재 단일 커넥션이다. 일반적으로 커넥션 풀을 사용하는 것이 단일 커넥션을 사용하는 것보다 일반적으로 더 효율적인데 그 이유는 다음과 같다.
따라서 위 커넥션 코드를 커넥션 풀로 관리되도록 리팩토링하였다.
const express = require('express')
const ejs = require('ejs')
const bodyParser = require('body-parser')
const mysql = require('mysql2');
require('dotenv').config();
const app = express()
const port = 3000
app.set('view engine', 'ejs');
app.set('views', './views')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse JSON
app.use(bodyParser.json())
// MySQL connection Pool :
// MySQL 커넥션을 사용할 때는 주로 커넥션 풀을 이용하여 관리하는 것이 권장
// 여러 요청이 동시에 처리될 때 효율적으로 커넥션을 관리
const connectionPool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PW,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
connectionLimit: 10, // 최대 연결 수 설정
insecureAuth: true,
});
// MySQL connection check
connectionPool.getConnection((err, connection) => {
if (err) {
console.error('MySQL에 연결 중 에러 발생:', err);
} else {
console.log('MySQL에 연결되었습니다.');
connection.release();
}
});
...
라우터 중 post요청 부분의 코드도 connectionPool을 통해서 진행되도록 수정하였다.
app.post('/api/contact', (req, res) => {
const name = req.body.name;
const phone = req.body.phone;
const email = req.body.email;
const memo = req.body.memo;
const SQL_Query = `INSERT INTO contact(name, phone, email, memo, create_at, modify_at) VALUES ('${name}','${phone}','${email}','${memo}',NOW(), NOW())`;
connectionPool.query(SQL_Query, (err, result) => {
if (err) {
console.error('데이터 삽입 중 에러 발생:', err);
res.status(500).send('내부 서버 오류');
} else {
console.log('데이터가 삽입되었습니다.');
res.send("<script>alert('문의사항이 등록되었습니다.'); location.href='/'</script>");
}
});
});
[Node.js] 웹 애플리케이션 아키텍처 고도화: MVC 패턴, Fetch API 전환 및 REST 아키텍처 심화 (3) | 2025.01.20 |
---|---|
[Node.js] Express.js와 MySQL로 구현하는 CRUD 기능: 조회, 삭제, 수정 및 RESTful API (0) | 2025.01.20 |
[Node.js] EJS로 동적 웹 페이지 만들기: Express와 함께하는 실습 (2) | 2025.01.13 |
[Node.js] 서버 구현 및 API 테스트: Express와 POSTMAN 활용 (2) | 2025.01.13 |
[Node.js] 타입스크립트의 제네릭과 모듈: 효율적인 코드 재사용과 관리 방법 (0) | 2025.01.10 |