지금까지는 일일히 입력값을 검증했지만, express-validator 를 외부 라이브러리를 npm에서 받아 사용하기로 했어요.
.post(body('userId').notEmpty().isInt().withMessage('userId must be a number'),
body('name').notEmpty().isString().withMessage('name must be a string')
,(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) res.status(400).json({"message": errors.array()[0].msg});
const { name, userId } = req.body;
let sql = `INSERT INTO channels (name, user_id) VALUES (?, ?)`;
let values = [name, userId];
conn.query(sql, values, (err, results) => {
if (err) return res.status(500).json(err);
res.status(201).json(results);
})
})
body 에 올 속성을 메소드 체이닝으로 직접 접근해서 검증할 수 있어요.

isint() 를 걸어놨더니 errors 객체의 msg 를 가져왔어요.
여기서 if (!errors.isEmpty()) 대신에 If(errors) 를 쓰고싶어도 JS는 {}를 true로 변환하기 때문에 사용할 수 없어요.
validation 과정에서 유효성 검사에 실패하면 error 객체가 반환돼요.
conn.query(sql, userId,
(err, results) => {
if (err) {
console.error("Database Error:", err);
return res.status(500).json({
"message": "서버 내부 오류가 발생했습니다. 잠시 후 다시 시도해주세요."
});
}
if (results.length) res.json(results);
else res.status(404).json({"message": "No Channel Found"});
})
})
이 error 객체는 서비스 정보가 유출되기 때문에 디버깅용 로그만 찍고, 유저에게는 공개하지 않아야해요.
함수 내부에서 return을 사용하면 종료와 함께 원하는 결과를 반환시킬 수 있어요.
그래서 if문 내부에서 return을 사용하게 되면 else를 사용하지 않아도 자동으로 함수가 종료되기 때문에 함수가 조금이라도 깔끔하게 보일 수 있다.
/channels 전체 조회 요청과 /channels + body에 userId를 넣는 개별 조회 요청이 요청을 받는 서버 입장에서 헷갈려요.
사실 GET 요청은 body를 통해 받는 게 안티패턴이기 때문에 이럴 일은 많지는 않겠지만, 코드에 따라 우선순위가 갈린다고 해요.
const sql = 'UPDATE channels SET name=? WHERE id = ?'
const values = [name,id];
conn.query(sql, values,
(err, results) => {
if (err) {
console.error("Database Error:", err);
return res.status(500).json({
"message": "서버 내부 오류가 발생했습니다. 잠시 후 다시 시도해주세요."
});
}
if (results.affectedRows === 0) {
return res.status(404).json({"message": `${id} Channel Not Found`});
}
return res.json({
"message": "Channel Updated Successfully",
});
})
put은 affectedRows 의 개수로 구분하는 게 중요해요.
요청 결과 row의 갯수가 0이면 404를 반환하기로 했어요.
다만 유효성 검사하는 부분이 너무 dry 원칙을 어기는 것 같아서 공통으로 빼야할 필요성이 있어요.
const validate = (req, res, next) => {
const errors = validationResult(req);
if (errors.isEmpty()) {
next();
}
return res.status(400).json({"message": errors.array()[0].msg});
}
그래서 다음과 같이 미들웨어를 분리했고,
router
.route('/')
.get([
body('userId').notEmpty().isInt().withMessage('userId must be a number'),
validate
],
(req, res) => {
let { userId } = req.body;
다음과 같이 미들웨어를 핸들러에 등록했어요.
미들웨어에서 next()를 명시해야 다음 핸들러로 넘어가져요.