[DevCamp] 유효성 검사 express-validator

동건·2025년 2월 27일
0

DevCamp

목록 보기
19/85

📌 유효성 검사와 express-validator

기존 channels.js 코드에서 데이터를 검증하는 기능이 부족하고,
에러 처리 방식이 일관되지 않은 문제가 있었다.

그래서 오늘은 유효성 검사에 대해 알아보는 시간을 가졌다.

이번 리팩토링에서는 express-validator를 활용하여 입력값 검증을 추가하고,
데이터베이스 조회 및 조작 시 발생할 수 있는 예외 처리를 강화했다.


1. express-validator 설치 방법

리팩토링된 코드에서 express-validator를 사용하므로, 먼저 패키지를 설치해야 한다.

npm install express-validator

설치가 완료되면, require('express-validator')를 통해 사용할 수 있다.

자세한 사용법은 아래의 링크를 통해 확인할 수 있다.

express-validator 공식 링크


2. 주요 변경 사항 요약

express-validator를 활용한 검증 추가

  • 기존 코드에서는 요청 본문(body)나
    URL 파라미터(param)에 대한 유효성 검사가 없었다.
  • 새로운 코드에서는 express-validator
    body(), param()을 사용해 데이터 타입 및 필수 입력값을 검증한다.

✅ 일관된 에러 처리

  • 기존 코드에서는 if-else 문으로 응답을 처리했지만,
    에러 발생 시 명확한 에러 메시지를 반환하지 않았다.
  • 새로운 코드에서는 데이터베이스 오류와
    유효성 검증 오류를 validationResult()를 통해 클라이언트에게 전달하도록 했다.

✅ RESTful API 방식 유지 및 코드 가독성 향상

  • 기존 코드에서 존재하던 불필요한 변수 선언 및 처리 방식 개선했다.
  • SQL 쿼리 실행 후 반환되는 결과를 affectedRows를 활용하여 응답을 정교화했다.

3. 기존 코드와 변경된 코드 비교

3.1 GET /channels - 사용자별 채널 목록 조회

📌 기존 코드

router.route('/')
    .get((req , res) => {
        let {user_id} = req.body;
        let channels = [];

        let sql = `SELECT * FROM channels WHERE user_id = ?`
        if(user_id){
            conn.query(sql, user_id, function(err, results){
                if(results){
                    channels = results;
                } else {
                    notFoundChannel(res);
                }
            });
        } else {
            res.status(400).json({ message: "잘못된 접근" });
        }
    });

🔄 변경된 코드

router.route('/')
    .get([
            body('user_id').notEmpty().isInt().withMessage('숫자를 입력해주세요.'),
            validate
        ], (req , res) => {
            let { user_id } = req.body;
            let sql = `SELECT * FROM channels WHERE user_id = ?`;

            conn.query(sql, user_id, function(err, results){
                if (err) {
                    return res.status(400).json({ message: err });
                }
                if (results.length) {
                    res.status(200).json(results);
                } else {
                    res.status(404).json({ message: "채널 정보를 찾을 수 없습니다." });
                }
            });
        });

✨ 개선된 점

  1. body('user_id').notEmpty().isInt()를 사용해 user_id 값이 비어있거나 정수가 아닌 경우 사전에 검증.
  2. notFoundChannel() 함수 제거 후 일관된 에러 메시지를 직접 반환.
  3. 데이터베이스 오류 발생 시 에러 메시지를 클라이언트에게 반환.

3.2 POST /channels - 새로운 채널 생성

📌 기존 코드

router.route('/')
    .post((req , res) => {
        let {name, user_id} = req.body;
        user_id = parseInt(user_id);
        
        if(name && user_id){
            let sql = `INSERT INTO users (name, user_id) VALUES (?, ?)`;
            let values = [name, user_id];
            conn.query(sql, values, function (err, results) {
                res.status(201).json(results);
            });
        } else {
            res.status(400).json({ message: "잘못된 접근" });
        }
    });

🔄 변경된 코드

router.route('/')
    .post([
            body('user_id').notEmpty().isInt().withMessage('숫자를 입력해주세요.'),
            body('name').notEmpty().isString().withMessage('문자열을 입력해주세요.')
        ], (req , res) => {
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }

            const { name, user_id } = req.body;
            let sql = `INSERT INTO channels (name, user_id) VALUES (?, ?)`;
            let values = [name, user_id];
            conn.query(sql, values, function (err, results) {
                if (err) {
                    return res.status(400).json({ message: err });
                }
                res.status(201).json(results);
            });
        });

✨ 개선된 점

  1. body()를 이용한 입력값 검증 추가.
  2. validationResult()를 활용해 유효성 검사 실패 시 클라이언트에 오류 반환.
  3. INSERT INTO usersINSERT INTO channels로 수정 (테이블명 오류 수정).

3.3 PUT /channels/:id - 채널 정보 수정

📌 기존 코드 문제점

  • 채널을 수정할 때 db.get(id)를 사용하여 데이터를 가져오는데, 이는 DB 연동이 아닌 메모리 기반 객체(db)를 사용.
  • UPDATE SQL 쿼리를 사용하지 않고, 직접 객체를 수정하는 방식으로 잘못된 접근.

🔄 변경된 코드

router.route('/:id')
    .put([
            param('id').notEmpty().withMessage('숫자를 입력해주세요.'),
            body('name').notEmpty().isString().withMessage('수정할 채널명을 다시 확인해주세요.')
        ], (req , res) => {
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }
    
            let { id } = req.params;
            let { name } = req.body;
    
            let sql = `UPDATE channels SET name = ? WHERE id = ?`;
            let values = [name, id];
    
            conn.query(sql, values, (err, results) => {
                if (err) {
                    return res.status(400).json({ message: err });
                }
    
                if (results.affectedRows === 0) {
                    return res.status(404).json({ message: "채널 정보를 찾을 수 없습니다." });
                } else {
                    res.status(200).json(results);
                }
            });
        });

✨ 개선된 점

  1. DB에서 데이터를 조회하는 방식으로 변경 (db.get(id) 제거, UPDATE 쿼리 적용).
  2. 입력값 검증 추가 (body('name').notEmpty().isString()).
  3. affectedRows를 확인하여 존재하지 않는 채널을 수정하려는 경우 적절한 응답 반환.

4. 🔨 TIL

이번 리팩토링을 통해 express-validator를 활용하여
입력값 검증을 추가하고, 일관된 에러 처리를 구현했다.
또한 RESTful API 설계를 유지하면서 SQL 쿼리를 올바르게 적용하는 방식으로 개선했다.
앞으로 개발 시 데이터 검증과 에러 처리의 중요성을 고려하며
코드를 작성하는 것이 필요하고 느꼈다. 🚀

profile
배고픈 개발자

0개의 댓글