TIL

23/11/22 TIL __ express validator ์‚ฌ์šฉ๊ธฐ

GABOJOK 2023. 11. 22. 23:50

 

 

๐Ÿž๏ธ   ์ƒํ™ฉ

ํŒ€๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด๋ฒˆ์—๋Š” express validator๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

์ง€๋‚œ๋ฒˆ ๊ฐœ์ธ๊ณผ์ œ๋•Œ joi๋ฅผ ์‚ฌ์šฉํ•ด ๋ดค๋Š”๋ฐ ๊ตณ์ด ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š”,

์•„๋ฌด๋ž˜๋„ express ํ™˜๊ฒฝ์—์„œ๋Š” express validator๊ฐ€ ํšจ์œจ์ด ์ข‹๋‹ค๋Š” ๋ง์ด ์žˆ์–ด์„œ ์‚ฌ์šฉํ•ด ๋ณด๊ณ  ์‹ถ์—ˆ๋‹ค.

 

์ฒ˜์Œ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค ๋ณด๋‹ˆ ๊ณต๋ถ€๊ฐ€ ํ•„์š”ํ–ˆ๊ณ , ์‹œ๊ฐ„์ด ์ข€ ๊ฑธ๋ ธ๋‹ค. 

joi๋ž‘์€ ์‚ฌ์šฉ๋ฒ•์ด ์ข€ ๋‹ฌ๋ž๋‹ค.

 

 

 

 

๐Ÿฃ   express validator 

 

 

์ผ๋‹จ ๊ณต์‹๋ฌธ์„œ์™€ ๋งŽ์€ ๋ธ”๋กœ๊ทธ๋“ค์„ ๋’ค์ ธ๊ฐ€๋ฉฐ ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ๋ฒ•๋“ค์„ ๋ณด์•˜๋‹ค.

๋ณดํ†ต router ์˜ ๋ฏธ๋“ค์›จ์–ด๋กœ ๋„ฃ์–ด์ฃผ๋˜๋ฐ, ๋‚˜๋Š” ๋”ฐ๋กœ ๋ฏธ๋“ค์›จ์–ด๋กœ ๋นผ๊ณ  ์‹ถ์–ด์„œ ์ข€๋” ์ฐพ์•„๋ดค๋‹ค. 

๊ทธ๊ฒŒ ์ข€ ๋” ๋ณด๊ธฐ ํŽธํ• ๋“ฏ ํ•ด์„œ ๋‹ค๋ฅธ ํŒŒ์ผ์— ๋‘๋ ค๊ณ  ํ–ˆ๋˜๊ฒƒ!

 

const { body, validationResult } = require('express-validator');

// ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋Š” ์‹œ์ ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆ
app.post('/register', [
  body('username').isLength({ min: 3, max: 30 }).isAlphanumeric().notEmpty(),
  body('email').isEmail().notEmpty(),
  body('password').isLength({ min: 3, max: 30 }).notEmpty(),
], (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    // ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง
    return res.status(400).json({ errors: errors.array() });
  }
  // ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•œ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง
  // ...
});

 

 

๋ณดํ†ต์€ ์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋‚˜๋Š” ๋”ฐ๋กœ ๋นผ๊ณ ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ–ˆ๋‹ค.

ํ•œ๊ฐœ์˜ ๋ณ€์ˆ˜์— ๋ฐฐ์—ด์„ ๋‹ด๋Š”๋ฐ,  body().isEamil() ๊ณผ ๊ฐ™์€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌํ•˜๋Š” ์• ๋“ค์„ ๋‹ด์•„๋‘๊ณ , ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด๋‘”๋‹ค.

๊ทธ ํ•จ์ˆ˜๋Š” ์—๋Ÿฌ๋ฅผ ์žก์•„์„œ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. 

๋งŒ๋“ค์–ด๋‘” ๋ณ€์ˆ˜๋ฅผ  exports ํ•ด์„œ router์˜ ๋ฏธ๋“ค์›จ์–ด๋กœ ๋„ฃ์–ด์ค€๋‹ค. 

 

์•„๋ž˜๋Š” ์‹ค์ œ๋กœ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ถ„์ด๋‹ค. 

 

validator.js 

const errorMsgMiddleware = (req, res, next) => {
	const errors = validationResult(req);
	if (errors.isEmpty()) {
		return next();
	}
	res.render('blank', { message: errors.array()[0].msg });
};

const registerValidator = [
	body('name')
		.notEmpty()
		.trim()
		.withMessage(`์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”`)
		.custom(value => {
			if (/\s/.test(value)) {
				throw new Error('์ด๋ฆ„์— ๊ณต๋ฐฑ์„ ํฌํ•จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค');
			}
			return true;
		}),

	body('email')
		.notEmpty()
		.withMessage('์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”')
		.isEmail()
		.normalizeEmail()
		.withMessage('์ด๋ฉ”์ผ์„ ํ™•์ธํ•ด ์ฃผ์„ธ์š”'),

	body('password')
		.notEmpty()
		.withMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”')
		.isLength({ min: 6 }, { max: 10 })
		.withMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ 6์ž๋ฆฌ ์ด์ƒ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”')
		.custom(value => {
			if (/\s/.test(value)) {
				throw new Error('๋น„๋ฐ€๋ฒˆํ˜ธ์— ๊ณต๋ฐฑ์„ ํฌํ•จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค');
			}
			return true;
		}),

	body('passwordRe')
		.custom((value, { req }) => {
			if (value !== req.body.password) {
				throw new Error('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•ด ์ฃผ์„ธ์š”');
			}
			return true;
		})
		.withMessage('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•ด ์ฃผ์„ธ์š”'),

	body('description').default('์•ˆ๋…•ํ•˜์„ธ์š”!'),
	errorMsgMiddleware,
];

 

 

์‚ฌ์šฉํ•˜๋ฉด์„œ express validator์™€ joi์ค‘ ์–ด๋–ค๊ฒŒ ๋” ํšจ์œจ์ ์ธ์ง€ ๋Š๊ปด๋ณด๊ณ  ์‹ถ์—ˆ์ง€๋งŒ, 

์•„์‰ฝ๊ฒŒ๋„ ์ „ํ˜€ ๋Š๋ผ์งˆ ๋ชปํ–ˆ๋‹ค.

๋‹ค๋งŒ ๋‘๊ฐœ์˜ ์ฐจ์ด๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ

joi๋Š” ์Šคํ‚ค๋งˆ ๋‹จ๊ณ„์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ด๊ณ , 

express validator๋Š” ๋ฏธ๋“ค์›จ์–ด ๋‹จ๊ณ„์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋งŽ์ด ์“ฐ์ธ๋‹ค.

 

 

์ฐจ์ด๋ฅผ ํฌ๊ฒŒ ๋Š๋ผ์ง€ ๋ชปํ–ˆ๋˜ ์ด์œ ์ค‘ ํ•˜๋‚˜๋Š”

๋‚˜๋Š” joi ๋ฅผ ์Šคํ‚ค๋งˆ ๋‹จ๊ณ„์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜์ง€ ์•Š๊ณ , ๋ฏธ๋“ค์›จ์–ด๋กœ ๋นผ์„œ ์ง„ํ–‰ํ–ˆ๋Š”๋ฐ 

์ด ๋ถ€๋ถ„๋•Œ๋ฌธ์— ๋” ๋น„์Šทํ•˜๊ฒŒ ๋Š๊ปด์กŒ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. 

 

 

 

 

 

์•„๋ž˜๋Š” joi๋ฅผ ์Šคํ‚ค๋งˆ ๋‹จ๊ณ„์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•˜๋Š” ์˜ˆ์‹œ์ด๋‹ค. 

const Joi = require('joi');

// ์‚ฌ์šฉ์ž(User) ํ…Œ์ด๋ธ”์˜ ์Šคํ‚ค๋งˆ
const userSchema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),
  email: Joi.string().email().required(),
  password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).required(),
  // ์ถ”๊ฐ€ ํ•„๋“œ ๋ฐ ๊ทœ์น™๋“ค...
});

// ๊ฒŒ์‹œ๋ฌผ(Post) ํ…Œ์ด๋ธ”์˜ ์Šคํ‚ค๋งˆ
const postSchema = Joi.object({
  title: Joi.string().required(),
  content: Joi.string().required(),
  authorId: Joi.number().required(), // ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž ID๋กœ ๋งคํ•‘๋˜๋Š” ์™ธ๋ž˜ํ‚ค
  // ์ถ”๊ฐ€ ํ•„๋“œ ๋ฐ ๊ทœ์น™๋“ค...
});

// ๋Œ“๊ธ€(Comment) ํ…Œ์ด๋ธ”์˜ ์Šคํ‚ค๋งˆ
const commentSchema = Joi.object({
  content: Joi.string().required(),
  postId: Joi.number().required(), // ์˜ˆ๋ฅผ ๋“ค์–ด ๊ฒŒ์‹œ๋ฌผ ID๋กœ ๋งคํ•‘๋˜๋Š” ์™ธ๋ž˜ํ‚ค
  userId: Joi.number().required(), // ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž ID๋กœ ๋งคํ•‘๋˜๋Š” ์™ธ๋ž˜ํ‚ค
  // ์ถ”๊ฐ€ ํ•„๋“œ ๋ฐ ๊ทœ์น™๋“ค...
});

// ์œ„์—์„œ ์ •์˜ํ•œ ์Šคํ‚ค๋งˆ๋ฅผ ์ด์šฉํ•˜์—ฌ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
// ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ƒ์„ฑ ์‹œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ
app.post('/users', (req, res) => {
  const { error, value } = userSchema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.details[0].message });
  }
  // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ, ์‚ฌ์šฉ์ž ์ƒ์„ฑ ๋กœ์ง ์ˆ˜ํ–‰...
});

// ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ ์‹œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ
app.post('/posts', (req, res) => {
  const { error, value } = postSchema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.details[0].message });
  }
  // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ, ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ ๋กœ์ง ์ˆ˜ํ–‰...
});

// ๋Œ“๊ธ€ ์ƒ์„ฑ ์‹œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ
app.post('/comments', (req, res) => {
  const { error, value } = commentSchema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.details[0].message });
  }
  // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ, ๋Œ“๊ธ€ ์ƒ์„ฑ ๋กœ์ง ์ˆ˜ํ–‰...
});

 

 

 

 

๋‘˜๋‹ค ์‚ฌ์šฉํ•ด ๋ณด๋‹ˆ, ๊ฐœ์ธ์ ์œผ๋กœ joi๊ฐ€ ๋” ๋ณด๊ธฐ ํŽธํ•˜๋‹ค๊ณ  ๋Š๊ปด์กŒ๋‹ค.

์†๋„ ์ฐจ์ด๋Š” ์‹ค์ œ๋กœ ์ฒด๊ฐํ•˜๊ธฐ์—๋Š” ์—†์—ˆ๋‹ค.

๋‹ค์Œ์—๋Š”  joi๋ฅผ ์Šคํ‚ค๋งˆ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•ด ๋ด์•ผ๊ฒ ๋‹ค.

 

 

 

 

์ฐธ๊ณ ํ•œ ์‚ฌ์ดํŠธ

https://express-validator.github.io/docs/api/validation-chain/#optional

 

ValidationChain | express-validator

The validation chain contains all of the built-in validators, sanitizers and utility methods to fine

express-validator.github.io