๐๏ธ ์ํฉ
ํ๊ณผ์ ๋ฅผ ์งํํ๋ฉด์, ์ ํจ์ฑ ๊ฒ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด๋ฒ์๋ 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 ๋ฅผ ์คํค๋ง ๋จ๊ณ์์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์งํํ์ง ์๊ณ , ๋ฏธ๋ค์จ์ด๋ก ๋นผ์ ์งํํ๋๋ฐ
์ด ๋ถ๋ถ๋๋ฌธ์ ๋ ๋น์ทํ๊ฒ ๋๊ปด์ก๋ ๊ฒ ๊ฐ๋ค.
![](https://t1.daumcdn.net/keditor/emoticon/niniz/large/025.gif)
์๋๋ 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