
1️⃣ connection 모듈 만들기
connection을 골라볼 수 있다.const mysql = require('mysql2/promise');
// Create the connection to database
async function connectToDatabase() {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: '1234',
database: 'Youtube', // 데이터베이스 이름을 'Youtube'로 설정
dateStrings: true,
});
// A simple SELECT query
try {
const [results, fields] = await connection.query( // await를 사용하여 쿼리 결과가 올 때까지 기다립니다. 쿼리의 결과는 results와 fields라는 두 가지 값으로 반환됩니다.
'SELECT * FROM `users`' // results: 데이터베이스에서 가져온 행들의 배열, fields: 쿼리 결과에 대한 메타데이터
);
let {id, email, name, created_at} = results[0]
console.log(id);
console.log(email);
console.log(name);
console.log(created_at);
} catch (err) {
console.log(err);
}
}
connectToDatabase();
// 이 함수는 데이터베이스에 연결하고, 쿼리를 실행한 후 결과를 처리하는 비동기 함수입니다.
// connectToDatabase()를 호출하여 실제로 이 함수가 실행되도록 합니다.
2️⃣ 에러가 발생한다 왜 그럴까? 코드를 고쳐서 사용해보자
const mysql = require('mysql2/promise');
// MySQL에 비동기적으로 연결
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '1234',
database: 'Youtube', // 데이터베이스 이름을 'Youtube'로 설정
dateStrings: true, // 날짜를 문자열로 반환
});
// 연결을 Promise로 내보냄
module.exports = connection;
const connPromise = require('../mariadb'); // mariadb 모듈에서 비동기적으로 반환되는 connection 객체를 Promise로 불러옴
async function runQuery() {
// 비동기 함수로, 데이터베이스 작업이 완료될 때까지 기다릴 수 있음
const conn = await connPromise; // 'connPromise'는 Promise를 반환하므로, await로 연결 객체(conn)가 반환될 때까지 기다림
const [results, fields] = await conn.query(
'SELECT * FROM `users`'
);
// 데이터베이스에서 'users' 테이블의 모든 데이터를 가져오는 쿼리 실행
// 쿼리의 결과는 'results'에 저장되고, 필드 메타데이터는 'fields'에 저장됨
// 쿼리가 완료될 때까지 await로 기다림
let { id, email, name, created_at } = results[0];
// 'results' 배열에서 첫 번째 레코드를 구조 분해 할당하여 id, email, name, created_at 값을 변수에 저장
console.log(id); // id 값 출력
console.log(email); // email 값 출력
console.log(name); // name 값 출력
console.log(created_at); // created_at 값 출력
}
runQuery();
// runQuery 함수를 호출하여 실행, 데이터베이스에 연결하고 쿼리 결과를 콘솔에 출력함
잘 출력되는 것을 확인할 수 있음

위에서 비동기 함수를 계속 사용한 이유는
1️⃣ 유튜브 프로젝트의 users를 db에 연동해보자


2️⃣ 코드를 맞게 고쳐보자
const connPomise = require('../mariadb'); // Promise 기반의 mariadb 연결 객체 가져옴
async function runQuery() {
const conn = await connPromise;
const [results, fields] = await conn.query(
`SELECT * FROM users Where email = ${email}`,
() => { res.json(results) }
);
}
// 회원 개별 조회
.get((req, res) => {
let {email} = req.body // {}는 비구조화, id 값을 따로 빼서 사용
runQuery();
})
특정 이메일 조회 SELECT * FROM Youtube.users WHERE email = 'kim@mail.com';를 하는 것으로 회원정보 개별 조회를 해보자

값을 잘 가져오는지 확인해보기 위해 body값에 이메일을 넣어 잘 반환하는지 확인해 보니 에러가 발생한다....

1️⃣ 에러를 찾아보자
SELECT * FROM users Where email = ${email}로 이메일을 템플릿 문자열로 바꾼 것인데 이것이 원인일 수도 있을 거 같다.
2️⃣ 에러를 해결하기 전 코드 수정
mysql2/promise모듈을 사용하였기 때문이다.mysql2/promise모듈을 사용하면 conn.query는 Promise를 반환하므로, await 또는 .then()을 사용해야 했었다. const mysql = require('mysql2'); // ('mysql2/promise')모듈에서 변경
// MySQL에 비동기적으로 연결
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '1234',
database: 'Youtube', // 데이터베이스 이름을 'Youtube'로 설정
dateStrings: true, // 날짜를 문자열로 반환
});
// 연결을 Promise로 내보냄
module.exports = connection;
const conn = require('../mariadb'); // Promise 기반의 mariadb 연결 객체 가져옴
conn.query(
'SELECT * FROM users WHERE email = ?', email, // email 값을 바인딩
function(err, results, fields) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
}
);

3️⃣ 반환되는 값의 특이점
[
{
"id": 3,
"email": "chim@mail.com",
"name": "chimchak",
"password": "1234",
"contect": "010-3333-3333",
"created_at": "2024-09-24 18:40:12"
}
]
1️⃣ 회원 API 설계를 수정해보자
이전 미니프로젝트에서 설계한 API를 데이터베이스 연동에 맞게 수정해보자
1) 로그인 : POST/login (SQL문: SELECT)
2) 회원 가입 : POST/join (SQL문: INSERT)
3) 회원 개별 정보 조회 : GET/users (SQL문: SELECT)
4) 회원 개별 탈퇴 : DELETE/users (SQL문: DELETE)
2️⃣ 회원가입도 연결해보자
// 회원가입
router.post('/join', (req, res) => {
console.log(req.body)
if (req.body == {}) {
res.status(400).json({
message : `입력 값을 확인해주세여`
})
} else {
const {email, name, password, contect} = req.body // 바디에 해당 값이 들어 있다면
conn.query(
`INSERT INTO users (email, name, password, contect)
VALUES (?, ?, ?, ?)`, [email, name, password, contect], // SQL문으로 테이블에 등록을 해준다.
function(err, results, fields) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
}
);
}
})


1️⃣ DELETE와 로그인을 수정해보자
2️⃣ 회원 삭제 코드를 작성해보자
// 회원 개별 탈퇴
.delete((req, res) => {
let {email} = req.body // {}는 비구조화, id 값을 따로 빼서 사용
conn.query(
'DELETE FROM users WHERE email = ?', email, // email 값을 바인딩
function(err, results, fields) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
}
);
})
results 반환값이 특이함. 이 내용은 영향받은 행위, 정보 등을 표현해준 데이터임

데이터베이스를 확인해보니 잘 삭제가 되었음.

3️⃣ 로그인 코드도 작성해보자
// 로그인
router.post('/login', (req, res) => { // 먼저 email이 디비에 저장된 회원인지 확인해야
const {email, password} = req.body
let loginUser = {}
conn.query(
'SELECT * FROM users WHERE email = ?', email, // email 값을 바인딩
function(err, results, fields) {
if (results.length) { // results에 값이 있다면
loginUser = results[0] // 로그인 유저 객체에 results의 0번째 객체를 담아준다. 이전보다 코드가 쉬워짐
if (loginUser.password == password) { // 로그인 유저 객체의 비번과 같다면
res.status(200).json({
message : `${loginUser.name}님 로그인 되었습니다.`
})
} else {
res.status(400).json({
message : `비밀번호가 틀렸습니다.`
})
}
} else {
res.status(404).json({
message : `회원정보가 없습니다.`
})
}
}
)
})
로그인이 잘 되는 것을 확인할 수 있다.



로그인 코드에 if else가 너무 많으니 깔끔하게 정리해보자
router.post('/login', (req, res) => { // 먼저 email이 디비에 저장된 회원인지 확인해야
const {email, password} = req.body
conn.query(
'SELECT * FROM users WHERE email = ?', email, // email 값을 바인딩
function(err, results, fields) {
let loginUser = results[0]; // 로그인 유저 객체에 results의 0번째 객체를 담아준다. 이전보다 코드가 쉬워짐
if (loginUser && loginUser.password == password) { // results에 값이 있다면을 로그인유저가 있고 패스워드가 같으면으로 변경해줌
res.status(200).json({
message : `${loginUser.name}님 로그인 되었습니다.`
})
} else if (loginUser && loginUser.password != password) { // 로그인 유저는 있지만, 패스워드가 아니면
res.status(400).json({
message : `비밀번호가 틀렸습니다.`
})
} else {
res.status(404).json({
message : `회원정보가 없습니다.`
})
}
}
)
})
// 로그인
router.post('/login', (req, res) => { // 먼저 email이 디비에 저장된 회원인지 확인해야
const {email, password} = req.body
conn.query(
'SELECT * FROM users WHERE email = ?', email, // email 값을 바인딩
function(err, results, fields) {
let loginUser = results[0]; // 로그인 유저 객체에 results의 0번째 객체를 담아준다. 이전보다 코드가 쉬워짐
if (loginUser && loginUser.password == password) { // results에 값이 있다면을 로그인유저가 있고 패스워드가 같으면으로 변경해줌
res.status(200).json({
message : `${loginUser.name}님 로그인 되었습니다.`
})
} else {
res.status(404).json({
message : `이메일 또는 비밀번호가 틀렸습니다.`
})
}
}
)
})
1️⃣ 위에서 만든 코드를 리펙토링 해보자
const express = require('express')
const router = express.Router()
const conn = require('../mariadb') // MariaDB 연결 객체 가져옴
router.use(express.json()) // JSON 파싱 미들웨어 사용
// 로그인
router.post('/login', (req, res) => {
const { email, password } = req.body
let sql = 'SELECT * FROM users WHERE email = ?' // SQL 쿼리를 변수로 저장
conn.query(sql, email, (err, results) => {
let loginUser = results[0] // 로그인하려는 유저 정보를 첫 번째 결과에서 가져옴
if (loginUser && loginUser.password == password) { // 비밀번호 확인
res.status(200).json({
message: `${loginUser.name}님 로그인 되었습니다.`
})
} else {
res.status(404).json({
message: `이메일 또는 비밀번호가 틀렸습니다.`
})
}
})
})
// 회원가입
router.post('/join', (req, res) => {
let sql = `INSERT INTO users (email, name, password, contect) VALUES (?, ?, ?, ?)`
if (req.body == {}) { // 입력 값이 없을 경우 처리
res.status(400).json({
message: `입력 값을 확인해주세여`
})
} else {
const { email, name, password, contect } = req.body
conn.query(sql, [email, name, password, contect], (err, results) => {
res.json(results) // 회원가입 성공 시 결과 응답
})
}
})
router
.route('/users')
// 회원 개별 조회
.get((req, res) => {
const { email } = req.body
let sql = 'SELECT * FROM users WHERE email = ?'
conn.query(sql, email, (err, results) => {
if (err) {
return res.status(500).send('Database query failed') // 쿼리 에러 처리
}
res.json(results) // 회원 정보 조회 결과 응답
})
})
// 회원 개별 탈퇴
.delete((req, res) => {
const { email } = req.body
let sql = 'DELETE FROM users WHERE email = ?'
conn.query(sql, email, (err, results) => {
res.json(results) // 탈퇴 후 결과 응답
})
})
module.exports = router;
1️⃣ 채널 API 설계를 수정해보자
이전 미니프로젝트에서 설계한 API를 데이터베이스 연동에 맞게 수정해보자
1) 채널 개별 "생성" : POST/channels (SQL문: INSERT)
${channelTitle}님 채널을 응원합니다2) 채널 개별 "수정" : PUT/channels/:id (SQL문: INSERT)
채널명이 성공적으로 수정되었습니다. 기존: ${}-> 수정: ${}3) 채널 개별 "삭제": DELETE/channels/:id (SQL문: DELETE)
삭제되었습니다.4) 채널 전체 "조회": GET/channels (SQL문: SELECT)
5) 채널 개별 "조회": GET/channels/:id (SQL문: SELECT)
2️⃣ 채널 개별 조회부터 코드를 만들어보자
router
.route('/:id')
.get((req, res) => {
let {id} = req.params // req.params 객체에서 URL 경로에 포함된 id 값을 추출하여 id 변수에 저장
id = parseInt(id) // URL에서 문자열로 추출된 id를 정수로 변환
let sql = 'SELECT * FROM channels WHERE id = ?'
conn.query(sql, id, // email 값을 바인딩
function(err, results) {
if (results.length) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
} else {
notFoundChannel()
}
}
)
})

3️⃣ 채널 전체 조회도 해보자
.get((req, res) => {
let {userId} = req.body
let sql = 'SELECT * FROM channels WHERE user_id = ?'
conn.query(sql, userId,
function(err, results) {
if (results.length) {
res.status(200).json(results);
} else {
notFoundChannel(res)
}
}
)
})
데이터를 보내거나 틀리게 보내면 정상적으로 작동하는 것을 확인할 수 있다. 다만, 아무런 값도 안보내면 에러가 발생함



자바스크립트의 단축평가를 이용해서 이 문제를 해결해보자, 빈 데이터를 보내도 배드리퀘가 뜨지만, 데이터를 보내도 배드리퀘가 뜬다.
.get((req, res) => {
let {userId} = req.body
let sql = 'SELECT * FROM channels WHERE user_id = ?'
userId &&/*단축평가*/ conn.query(sql, userId, // 단축평가로 조건을 추가해주면 뒤 코드를 실행하지 않음(res를 보내지 못하고 무한로딩)
function(err, results) {
if (results.length) {
res.status(200).json(results); // 쿼리 결과를 클라이언트에 응답
} else {
notFoundChannel(res)
}
}
)
res.status(400).end() // 값을 보내지 않고 무한로딩을 끝내줌
})

// 채널 전체 조회
.get((req, res) => {
let {userId} = req.body
let sql = 'SELECT * FROM channels WHERE user_id = ?'
if (userId) { conn.query(sql, userId,
function(err, results) {
if (results.length) {
res.status(200).json(results); // 쿼리 결과를 클라이언트에 응답
} else {
notFoundChannel(res)
}
}
)} else {
res.status(400).end()
}
})
1️⃣ 채널 생성을 해보자
.post((req, res) => {
if (req.body.name){
const {name, userId} = req.body
let sql = `INSERT INTO channels (name, user_id) VALUES (?, ?)`
let values = [name, userId]
conn.query(sql, values,
function(err, results) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
}
)
} else {
res.status(400).json({
message : '요청 값을 제대로 보내주세요'
})
}
})



2️⃣ 값을 제대로 보내지 않았을 경우를 예외처리 해보자
.post((req, res) => {
const {name, userId} = req.body
if (name && userId){
let sql = `INSERT INTO channels (name, user_id) VALUES (?, ?)`
let values = [name, userId]
conn.query(sql, values,
function(err, results) {
res.json(results); // 쿼리 결과를 클라이언트에 응답
}
)
} else {
res.status(400).json({
message : '요청 값을 제대로 보내주세요'
})
}
})
👉 유효성 검사는 5강의로