DB 모듈화
mariadb.js 파일에 `module.exports = connection;` 로 모듈화 추출
db를 사용하려는 파일 user.js 파일에 `const conn = require("../mariadb");` 모듈화 사용
콘솔을 찍어보고, app.js 에서 실행 run 시켜본다면?
const conn = require("../mariadb");
// Simple query
conn.query("SELECT * FROM `users`", function (err, results, fields) {
var { id, name, email, created_at } = results[0];
console.log(id);
console.log(name);
console.log(email);
console.log(created_at);
});
와! app에서도 mariadb를 사용할 수 있게 됨!
DB로 user api 사용하기
- 로그인 : POST /login
- SELECT
- req : body (email, pwd)
- res : ${name}님 환영합니다. → 메인페이지
- 회원 가입 : POST /join
- INSERT
- req : body (email, name, password, contact)
- res : ${name}님 환영합니다. → 로그인 페이지
- 회원 개별 정보 조회 : GET /users/:id
- SELECT
- req : URL (userid)
- res : userid, name
- 회원 개별 탈퇴 : DELETE users/:id
- DELETE
- req : URL (email)
- res : ${name}님 다음에 또 뵙겠습니다. → 메인 페이지
- 마이페이지의 id데이터 대신 이메일 데이터로 유니크 처리
db의 email 데이터와, 사용자에게 받는 req.body 안의 email과 동일할때 회원 개별 조회 성공!
.get((req, res) => {
let { email } = req.body;
conn.query(
`SELECT * FROM users WHERE email = ${email}`,
function (err, results, fields) {
if (results.length) res.status(200).json({ result });
else res.status(404).json({ message: "회원 정보가 없습니다" });
}
);
})
그런데, results.length 에서 에러가 발생한다. undefined 발생!
이유는, json 객체 전달이 아닌, ${} 템플릿 문자열로 email을 받았기 때문이다.
문자를 받는 정석적인 방법은
`SELECT * FROM users WHERE email = ?`,
email,
result 반환형태 객체(배열)형태!
Prepared Statement 템플릿 문자열 대신 물음표 사용
쿼리 문자열에서 물음표 ? 를 사용해 변수의 위치를 나타내고,
위 방법처럼 ,콤마로 바로 뒤에 선언해 줄 수도 있고,
그 위치에 대응하는 값을 배열 형태로 전달할 수도 있다.
ex
app.post('/search', (req, res) => {
const searchTerm = req.body.searchTerm;
const query = `SELECT * FROM my_table WHERE column_name = ?`;
connection.query(query, [searchTerm], (error, results) => {
if (error) {
res.status(500).send('Error fetching data');
return;
}
res.json(results);
});
});
회원가입 INSERT
const { email, name, password, contact } = req.body;
conn.query(
`INSERT INTO users (email, name, password, contact) VALUES (?, ?, ?, ?)`,
[email, name, password, contact],
function (err, results, fields) {
res.status(201).json(results);
}
);
postman에서 회원가입 시켰을때, res로 results를 돌려받기로 했는데, 아무것도 돌려주지 않았다!
db를 확인해보면
id 6번에 잘 할당되었다!
INSERT를 하면, result는 따로 전달해주지 않는 것 같다!
탈퇴 DELETE
.delete((req, res) => {
const { email } = req.body;
conn.query(
`DELETE FROM users WHERE email = ?`,
email,
function (err, results, fields) {
res.status(201).json(results);
}
);
});
`affectedRows`로 코드가 동작했다는 것을 볼 수 있다. 상태를 전달해줌!
이때 삭제된 email을 삭제하려고 하면, `affectedRows`가 0으로 전달된다. 변경되지 않았다는 말.
이걸 404로 소통할지, 0값으로 소통할지는 정해야 할 규칙이다!
로그인 SELECT
router.post("/login", (req, res) => {
console.log(req.body); //userId, pwd
//email이 db에 저장된 회원인지
const { email, password } = req.body;
conn.query(
`SELECT * FROM users WHERE email = ?`,
email,
function (err, results) {
var loginUser = results[0];
if (loginUser && loginUser.password == password)
res
.status(200)
.json({ message: `${loginUser.name}님 로그인 되었습니다.` });
else
res.status(404).json({ message: "이메일 또는 비밀번호가 틀렸습니다" });
}
);
});
리팩토링
- 죽은 코드, 사용안하는 변수, 괄호 정리
- 주석 정리
- 문자열 오타 확인, 반복되는 기능 변수 할당
const { email, name, password, contact } = req.body;
let sql = `INSERT INTO users (email, name, password, contact) VALUES (?,?,?,?)`;
let values = [email, name, password, contact];
conn.query(sql, values, function (err, results) {
res.status(201).json(results);
});
DB로 channels api 사용하기
- 채널 생성 : POST `/channels`
- INSERT
- req : body (name,user_id)
- res 201 : ${name}님 채널을 응원합니다. >
다른 페이지?
- 채널 개별 수정 : PUT `/channels/:id`
- UPDATE
- req : URL (id), body (name)
- res 200 : 채널명이 성공적으로 수정되었습니다. 기존 :${} > 수정 : ${}
- 채널 개별 삭제 : DELETE /channels/:id`
- DELETE
- req : URL (id)
- res 200 : name 삭제되었습니다 > 메인페이지
- 채널 전체 "조회" : GET `/channels`
- SELECT
- req : body (user_id)
- res 200 : 채널 전체 데이터 list, json array
- 채널 개별 "조회" : GET `/channels/:id`
- SELECT
- req : URL(id)
- res 200 : 채널 개별 데이터
SELECT 채널 개별 조회
.get((req, res) => {
let { id } = req.params;
id = parseInt(id);
let sql = `SELECT * FROM channels WHERE id = ?`;
conn.query(sql, id, function (err, results) {
if (results.length) res.status(200).json(results);
else notFoundChannel(res);
});
})
function notFoundChannel(res) {
res.status(404).json({
message: "채널 정보를 찾을 수 없습니다.",
});
}
채널정보 404 보낼때, 함수 따로 뺀 notFoundChannel에 res 로 매개변수를 전달해 주어야 한다.
SELECT 회원의 채널 전체 조회
let sql = `SELECT * FROM channels WHERE user_id = ?`;
userId &&
conn.query(sql, userId, function (err, results) {
if (results.length) res.status(200).json(results);
else notFoundChannel(res);
});
res.status(400).end();
short-circuit evaluation
단축평가, 우선순위, 타입스크립트 && 로 묶어주기
만일, 안읽고 전송값이 없으면, status(400), end()로 종료시킨다.
종료시킨 코드가 에러를 발생시킨다!! > userId를 실행하고, 위에 404를 덮어씌우는 코드가 됨.
if문을 사용해서 해결한다.
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();
단축평가 편리하긴 한데, 로직이 조금 복잡해지거나 추가할때 문제를 발생시킨다.
*백엔드에서는 가급적 short-circuit 사용하지 말자
*추후에 미들웨어를 활용해 예외처리 하는 방법 배울것
INSERT 채널 개별 생성
name과 userId 에 대한 유효성 검사를 실행해야 한다.
//채널 개별 생성
.post((req, res) => {
const { name, userId } = req.body;
if (name && userId) {
let sql = `INSERT INTO users (name, user_id) VALUES (?,?)`;
let values = [name, userId];
conn.query(sql, values, function (err, results) {
res.status(201).json(results);
});
} else {
res.status(404).json({
message: "요청 값을 제대로 보내주세요.",
});
}
});
name과 userId의 형식은 int 인데, 문자열이 들어온다면, 404에러가 떠야하는데,
if 조건은 값이 존재할때 이기 때문에 201로 코드가 실행이 된다. sql 문도 실행되는데, 값은 삽입되지 않는다.
☑️ 배운 점
DB와 코드 연결하기! express, mariadb를 사용하니 한결 어렵지 않다고 느껴졌다.
conn.query > 많이 봤던 코드! 기능구현은 큰부분은 비슷한데, 각 기능마다의 예외를 고려해주는게 복잡하다. 코드를 잘 짤줄 알아도, 예외 처리해주는 사고를 길러야 할 것 같다.
백엔드에서는 어떤 예외처리를 만날지 모르기 때문에, 단축 평가 논리 계산법 사용 금지!
> 코테에서 코드의 길이를 짧게하기 위해 삼항연산자를 종종 사용했는데, 백엔드 구현 시에는 언제 또 복잡한 로직으로 수정될지 모르기 때문에, 가급적 if 문을 그대로 사용하는 것이 좋을것 같다.