Post

데브코스 TIL - Day 26

23년 12월 22일 강의를 들은 내용과 추가로 학습한 내용을 기록한 글입니다.

유효성 검사

사용자가 입력한 값에 대한 유효성(타당성)을 검사

express-validator

express-validator npm 문서

설치

1
npm install express-validator

사용방법

1
const { body, param, validationResult } = require("express-validator");

validationResult()로 유효성 검사 결과 받기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express = require("express");
const { query, matchedData, validationResult } = require("express-validator");
const app = express();

app.use(express.json());
app.get("/hello", query("person").notEmpty().escape(), (req, res) => {
  // 유효성 검사 확인
  const result = validationResult(req);
  if (result.isEmpty()) {
    const data = matchedData(req);
    return res.send(`Hello, ${data.person}!`);
  }

  res.send({ errors: result.array() });
});

app.listen(3000);

error.array() 결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[
  {
    type: 'field',
    value: undefined,
    msg: 'Invalid value',
    path: 'user_id',
    location: 'body'
  },
  {
    type: 'field',
    value: undefined,
    msg: 'user_id는 숫자여야합니다.',
    path: 'user_id',
    location: 'body'
  }
]

UPDATE, INSERT 했을 때 results 값

  • 성공/실패 => affectedRows,info 값만 다름
  • affectedRows로 성공/실패 여부 판단
1
2
3
4
5
6
7
8
9
{
    "fieldCount": 0,
    "affectedRows": 1,
    "insertId": 0,
    "info": "Rows matched: 1  Changed: 0  Warnings: 0",
    "serverStatus": 2,
    "warningStatus": 0,
    "changedRows": 0
}

전체 코드

channels

  • 자주 사용하는 유효성 검사는 별도로 변수로 분리하여 사용
  • validate함수 (유효성 검사 에러 유무 판별)
  • checkSqlError함수 (sql 에러 유무 판별)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const express = require("express");
const router = express.Router();
const conn = require("../mysql");
const { body, param, validationResult } = require("express-validator");

router.use(express.json());

const notFoundChannel = (res) => {
  res.status(404).send({ message: "채널 정보를 찾을수 없습니다." });
};

const validationBodyUserId = body("user_id")
  .notEmpty()
  .isInt()
  .withMessage("user_id는 숫자여야합니다.");
const validationBodyName = body("name")
  .notEmpty()
  .isString()
  .withMessage("채널명은 문자여야합니다.");
const validationParamId = param("id")
  .notEmpty()
  .withMessage("채널 아이디가 필요합니다.");

const validate = (req, res, next) => {
  const err = validationResult(req);

  if (err.isEmpty()) return next();
  return res.status(400).send(err.array()[1]);
};

const checkSqlError = (err, res) => {
  if (err) {
    console.log(err);
    return res.status(400).end();
  }
};

router
  .route("/")
  .get([validationBodyUserId, validate], (req, res, next) => {
    const { user_id } = req.body;
    const sql = "SELECT * from channels WHERE user_id = ?";

    conn.query(sql, user_id, (err, results) => {
      checkSqlError(err, res);

      if (results.length > 0) {
        res.status(200).send(results);
      } else {
        notFoundChannel(res);
      }
    });
  })
  .post(
    [validationBodyUserId, validationBodyName, validate],
    (req, res, next) => {
      const { name, user_id } = req.body;

      const sql = "INSERT INTO channels (name,user_id) VALUES (?,?)";
      const values = [name, user_id];

      conn.query(sql, values, (err, results) => {
        checkSqlError(err, res);

        res
          .status(201)
          .send({ message: `${user.name}님, 채널이 생성되었습니다.` });
      });
    }
  );

router
  .route("/:id")
  .get([validationParamId, validate], (req, res, next) => {
    const id = Number(req.params.id);
    const sql = "SELECT * from channels WHERE id = ?";

    conn.query(sql, id, (err, results) => {
      checkSqlError(err, res);

      if (results.length > 0) {
        res.status(200).send(results);
      } else {
        notFoundChannel(res);
      }
    });
  })
  .put([validationParamId, validationBodyName, validate], (req, res, next) => {
    const id = Number(req.params.id);
    const { name } = req.body;

    const sql = "UPDATE channels SET name = ? WHERE id = ?";
    const values = [name, id];

    conn.query(sql, values, (err, results) => {
      checkSqlError(err, res);
      if (results.affectedRows > 0) {
        res.status(200).send(results);
      } else {
        res.status(400).end();
      }
    });
  })
  .delete([validationParamId, validate], (req, res) => {
    const id = Number(req.params.id);
    const sql = "DELETE FROM channels WHERE id = ?";

    conn.query(sql, id, (err, results) => {
      checkSqlError(err, res);
      if (results.affectedRows > 0) {
        res.status(200).send(results);
      } else {
        res.status(400).end();
      }
    });
  });

module.exports = router;

users

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const express = require("express");
const router = express.Router();
const conn = require("../mysql");
const { body, validationResult } = require("express-validator");

router.use(express.json());

const validationBodyEmail = body("email")
  .notEmpty()
  .isEmail()
  .withMessage("이메일 형식이 아닙니다.");
const validationBodyName = body("name")
  .notEmpty()
  .isString()
  .withMessage("유저 이름은 문자여야합니다.");
const validationBodyContact = body("contact")
  .notEmpty()
  .isString()
  .withMessage("전화번호 확인해주세요");
const validationBodyPassword = body("pwd")
  .notEmpty()
  .isStrongPassword()
  .isString()
  .withMessage("비밀번호 확인해주세요");

const validate = (req, res, next) => {
  const err = validationResult(req);

  if (err.isEmpty()) return next();
  return res.status(400).send(err.array()[1]);
};

const checkSqlError = (err, res) => {
  if (err) {
    console.log(err);
    return res.status(400).end();
  }
};

router.post(
  "/join",
  [
    validationBodyEmail,
    validationBodyName,
    validationBodyPassword,
    validationBodyContact,
    validate
  ],
  (req, res, next) => {
    const { email, pwd, name, contact } = req.body;
    const sql =
      "INSERT INTO users (email,name,password,contact) VALUES (?,?,?,?)";
    const values = [email, name, pwd, contact];

    conn.query(sql, values, (err, results, fields) => {
      checkSqlError(err, res);
      res.status(201).send({ message: `${name}님, 환영합니다.` });
    });
  }
);

router.post(
  "/login",
  [validationBodyEmail, validationBodyPassword, validate],
  (req, res) => {
    const { email, pwd } = req.body;
    const sql = "SELECT * FROM users WHERE email = ?";

    conn.query(sql, [email], (err, results) => {
      checkSqlError(err, res);

      const [matchedEmail] = results;
      if (matchedEmail) {
        if (matchedEmail.password === pwd) {
          res
            .status(200)
            .send({ message: `${matchedEmail.name}님, 환영합니다.` });
        } else {
          res.status(400).send({ message: "비밀번호가 일치하지 않습니다." });
        }
      } else {
        res.status(400).send({ message: "일치하는 아이디가 없습니다." });
      }
    });
  }
);

router
  .route("/users")
  .get([validationBodyEmail, validate], (req, res) => {
    const { email } = req.body;
    const sql = "SELECT * FROM users WHERE email = (?)";

    conn.query(sql, [email], (err, results) => {
      checkSqlError(err, res);

      if (results.length > 0) {
        res.status(200).send(results[0]);
      } else {
        res.status(404).send({ message: "일치하는 아이디가 없습니다." });
      }
    });
  })
  .delete([validationBodyEmail, validate], (req, res) => {
    const { email } = req.body;
    const sql = "DELETE FROM users WHERE email = ? ";

    conn.query(sql, [email], (err, results) => {
      checkSqlError(err, res);

      if (results.affectedRows > 0) {
        res.status(200).send(results);
      } else {
        res.status(400).end();
      }
    });
  });

module.exports = router;
This post is licensed under CC BY 4.0 by the author.