유효성 검사 validation
사용자가 입력한 값(에 따른 결과값) 타당성,유효성을 확인하는 것
- userId : 값이 있어야 한다, 숫자
- 채널 name : 값이 있어야 한다, 문자
- 사람 name : 숫자 X, 문자열, 2글자 이상
express-validator
일일이 검사할 수 있지만, 외부모듈을 사용해 검사한다!
req.body, cokkies, headers, params, query의 값에 대해 서포트 할 수 있다,
userId 숫자 express-validator
req에서 직접 꺼내서 쓰지 말고, 콜백함수 실행 전에 모듈핸들러로 유효성 검사를 한다
//채널 개별 생성
.post(body("userId").notEmpty().isInt().withMessage('숫자 입력하자!'), (req, res) => {
const err = validationResult(req);
if (!err.isEmpty()) {
console.log(err.array());
}
//userId 문자열 입력시
[
{
type: 'field',
value: 'abc',
msg: '숫자 입력하자!',
path: 'userId',
location: 'body'
}
]
name 문자
여러개 유효성 처리 - 배열에 한번에 할당한다!
//채널 개별 생성
.post(
[
body("userId").notEmpty().isInt().withMessage("숫자 입력 필요"),
body("name").notEmpty().isString().withMessage("문자 입력 필요"),
],
(req, res) => {
const err = validationResult(req);
if (!err.isEmpty()) {
return res.status(400).json(err.array());
}
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.status(201).json(results);
});
}
);
if 문 없어도, 유효성 처리로 컨트롤 가능!!
userId 없을때 insert 에러 처리
`throw err`
sql insert 작업 시 없는 값(userId) 참조 무결성을 어길경우 404 err 발생시킨다.
conn.query(sql, values, function (err, results) {
if (err) {
//console.log(err);
return res.status(404).end();
}
res.status(201).json(results);
});
Error: Cannot add or update a child row: a foreign key constraint fails (`Youtube`.`channels`, CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
at Packet.asError (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\packets\packet.js:728:17)
at Query.execute (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\commands\command.js:29:26)
at Connection.handlePacket (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\connection.js:481:34)
at PacketParser.onPacket (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\connection.js:97:12)
at PacketParser.executeStart (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\packet_parser.js:75:16)
at Socket.<anonymous> (c:\Users\dh010\Desktop\DevCourse\스프린트2\youtube-demo\node_modules\mysql2\lib\connection.js:104:25)
at Socket.emit (node:events:514:28)
at addChunk (node:internal/streams/readable:545:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:495:3)
at Readable.push (node:internal/streams/readable:375:5) {
code: 'ER_NO_REFERENCED_ROW_2',
errno: 1452,
sqlState: '23000',
sqlMessage: 'Cannot add or update a child row: a foreign key constraint fails (`Youtube`.`channels`, CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)',
sql: "INSERT INTO channels (name, user_id) VALUES ('댄싱무지',100)"
}
channels 리팩토링
params에서 꺼내는 법? `const { body, param, validationResult } = require("express-validator");`
`if (!err.isEmpty()` 조건이 반복되는 것을 볼 수 있다. > 함수로 빼주기
UPDATE 채널 개별 수정
.put(
[
param("id").notEmpty().withMessage("채널 id 필요"),
body("name").notEmpty().isString().withMessage("채널명 오류"),
],
(req, res) => {
const err = validationResult(req);
if (!err.isEmpty()) {
return res.status(400).json(err.array());
}
let { id } = req.params;
id = parseInt(id);
let { name } = req.body;
let sql = `UPDATE channels SET name=? WHERE id=?`;
let values = [name, id];
conn.query(sql, values, function (err, results) {
if (err) {
console.log(err);
return res.status(404).end();
}
if (results.affectedRows == 0) return res.status(404).end();
else res.status(200).json(results);
});
}
)
id값 1 입력해서 제대로 실행시켰을때?
update됨!
id 값을 20으로 해도 sql문이 실행되는 코드 예외처리 해주어야 한다.
if (results.affectedRows == 0) return res.status(404).end();
else res.status(200).json(results);
DELETE 채널 개별 삭제
.delete(
param("id").notEmpty().isInt().withMessage("채널 id 필요"),
(req, res) => {
const err = validationResult(req);
if (!err.isEmpty()) {
return res.status(400).json(err.array());
}
let { id } = req.params;
id = parseInt(id);
let sql = `DELETE FROM channels WHERE id = ?`;
conn.query(sql, id, function (err, results) {
if (err) {
console.log(err);
return res.status(404).end();
}
if (results.affectedRows == 0) return res.status(404).end();
else res.status(200).json(results);
});
}
);
지금까지 작성한 코드의 집합체! > 함수로 빼낼 수 있을듯?
.status 코드
설계 단계에서 명확하게 규칙을 정하고 넘어가야 하는 부분!
검사 미들웨어 분리
err.isEmpty()를 함수로 분리한다. > 파일 내부에서 모듈화해서 미들웨어처럼 만드는 방법 `변수에 함수 담기`
const validate = (req, res) => {
const err = validationResult(req);
if (!err.isEmpty()) {
return res.status(400).json(err.array());
}
};
get()괄호 첫번째 인자는, 콜백함수를 호출하기 전에 실행해야할 코드를 모아둠
핸들러 : req 요청이 왔을때, 호출되는 메소드
router
.route("/")
//채널 전체 조회
.get(
[body("userId").notEmpty().isInt().withMessage("숫자 입력 필요"), validate],
(req, res) => {
그런데! 미들웨어로 핸들러 인자를 넘겨주면, 뒤의 콜백함수가 실행되지 않는다.
...해결은 다음글...
☑️ 배운 점
if 문으로 예외처리 대신, 유효성 처리로 조건을 할당할 수 있다!
오늘 팀원들과 WIL 회의에서 if 문에 대한 생각을 공유했는데, 이번 강의에서 유효성 검사로 조건을 처리할 수 있는 방법을 배워서 좋았다. 각 요청마다 거의 같은 예외처리를 해주어야 했기에 미들웨어 모듈로 추출할 수 있었다.
body와 param 값을 핸들러 인자 위치에, 배열로 여러개의 값을 담아서, 콜백함수 실행전에, 미리 실행할 수 있다는 점.
미들웨어 배열
미들웨어 또는 핸들러 함수를 사용하기 전에 요청을 처리하고 유효성을 검사하기 위한 미들웨어 배열이다.
배열은 Express.js에서 유효성 검사를 수행하는데 사용되는 일반적인 패턴이다. 여기서 각 요소는 미들웨어 함수를 나타낸다.
유효성 검사 Express-validator에 유용하고, 다양한 유효성 검사를 몰아서 할 수 있어 미들웨어 체인을 사용한다. 또한 로직 커스터마이징이 가능하기 때문에 생산성과 가독성을 높일 수 있다.
//예시 코드
const express = require('express');
const { body, validationResult } = require('express-validator');
const app = express();
// POST 요청을 처리하는 라우트 핸들러
app.post('/user', [
body("userId").notEmpty().isInt().withMessage("숫자 입력 필요"),
body("name").notEmpty().isString().withMessage("문자 입력 필요"),
validateInput,
], (req, res) => {
// 유효성 검사가 통과되었을 때 실행되는 코드
res.send('Validation passed');
});
// 커스텀 미들웨어 함수 - 유효성 검사 결과 처리
function validateInput(req, res, next) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next(); // 다음 미들웨어로 전달
}
app.listen(3000, () => console.log('Server started on port 3000'));