checkSchema(schema: Schema, defaultLocations?: Location[]): ValidationChain[] & ContextRunner
์ฃผ์ด์ง schema
๋ฅผ ๋ฐํ์ผ๋ก ํ๋ validation chains
์ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๊ณ express.js์ ๋ผ์ฐํธ์์ ๋ฏธ๋ค์จ์ด๋ก์ ์ฌ์ฉํ ์ ์๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์์ฒญ ๊ฐ์ฒด์ ๋ชจ๋ locations(body
, cookies
, headers
, params
, query
)์ ์๋ ํ๋๋ค์ด ๊ฒ์ฆ๋๋ค.
ํ์ง๋ง ์์ ์๊ฐ๋ locations๋ค ๋ชฉ๋ก์ defaultLocations
ํ๋ผ๋ฏธํฐ์ ํน์ location๋ค์ ๋ช
์ํ ๋ฐฐ์ด์ ์ธ์๋ก ๋๊ฒจ์ ๋ณ๊ฒฝํ ์ ์๋ค.
checkSchema(schema, ['body', 'query']);
๊ฐ ๊ฒ์ฆ๋ ํ๋์ location์ ์ธ๋ถ ์กฐ์ ํ๊ณ ์ถ๋ค๋ฉด, in
ํ๋กํผํฐ๋ฅผ ์ค์ ํ ์ ์๋ค. in
ํ๋กํผํฐ๋ defaultLocations
๋งค๊ฐ๋ณ์๋ณด๋ค ๋ ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋ค.
checkSchema()
๋ ๋ฏธ๋ค์จ์ด๋ฅผ
validation chain์ ๋นํธ์ธ ๊ฒ์ฆ์, sanitizers, ์ ํธ๋ฆฌํฐ ๋ฉ์๋๋ฅผ ํฌํจํ์ฌ ํน์ ํ๋์ ๋ํ ๊ฒ์ฆ ๋์์ ์กฐ์ ํ ์ ์๋ค.
validation chains๋ check()
ํจ์์ ์ํด ๋ง๋ค์ด์ง๋ฉฐ ๋ค์๊ณผ ๊ฐ์ ์ฌ์ฉ ์๋ก ์ฌ์ฉํ ์ ์๋ค.
oneOf()
or checkExact()
๋ฑ)์ ๋งค๊ฐ๋ณ์๋ก ์ฌ์ฉํ ์ ์๋ค.custom(validator: (value, { req, location, path }) => any): ValidationChain
์ปค์คํ ๊ฒ์ฆ์ ํจ์๋ฅผ ์ฒด์ธ์ ์ถ๊ฐํ๋ค.
ํ๋ ๊ฐ์ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ ํจ ๊ฐ์ผ๋ก ํ์ ๋๋ค.
๋ง์ฝ ์ปค์คํ ์์ฑ์๊ฐ falsy๊ฐ์ ๋ฐํํ๊ฑฐ๋, rejects๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๊ฑฐ๋, ์๋ฌ๋ฅผ ๋ฐํํ๋ค๋ฉด, ํด๋น ํ๋ ๊ฐ์ ์ ํจํ ๊ฐ์ด ์๋๋ผ๊ณ ํ์ ๋๋ค.
exists(options?: {
values?: 'undefined' | 'null' | 'falsy',
checkNull?: boolean,
checkFalsy?: boolean
}): ValidationChain
ํ๋๊ฐ ์กด์ฌํ๋์ง ํ์ธํ๋ ๊ฒ์ฆ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ค.
options.values
์ ๋ช
์๋ ๊ฐ์ ๋ฐ๋ผ ํ๋๊ฐ ์กด์ฌํ๋์ง ์กด์ฌํ์ง ์๋์ง ์ฌ๋ถ๊ฐ ๊ฒฐ์ ๋๋ฉฐ, ๊ธฐ๋ณธ๊ฐ์ undefined
๋ค.
options.values | Behavior |
---|---|
undefined | ํ๋ ๊ฐ์ด undefined ๋ผ๋ฉด ํ๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ค. |
null | ํ๋ ๊ฐ์ด undefined ํน์ null ์ด๋ผ๋ฉด ํ๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ค. |
falsy | ํ๋ ๊ฐ์ด falsy ๊ฐ์ด๋ผ๋ฉด('' ,0 ,false ,null ,undefined ) ํ๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๋ค. |
options.checkNull
๊ณผ options.checkFalsy
๋ deprecated ์ต์
์ด๋ค. options.values
๋ก null
, falsy
๋ฅผ ์ฌ์ฉํ๋ผ.
๐จ.exists()
๋ ๋ค๋ฅธ ๊ฒ์ฆ๊ธฐ๋ sanitizers๋ฅผ ์ถ๊ฐํ์ง ์๋ ๊ฒฝ์ฐ์๋ง ํ์ํ๋ค.
isArray(options?: { min?: number; max?: number }): ValidationChain
ํ๋ ๊ฐ์ด ๋ฐฐ์ด์ธ์ง ํ์ธํ๋ ๊ฒ์ฆ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ์ Array.isArray()
ํจ์์ ์ ์ฌํ๋ค.
์ต์
์ผ๋ก options.min
, options.max
๋ฅผ ์ถ๊ฐํ์ฌ ํ์ฉ ๋ฐฐ์ด ๊ธธ์ด๋ฅผ ์ ํํ ์ ์๋ค.
// Verifies that the friends list is an array
body('friends').isArray();
// Verifies that ingredients is an array with length >= 0
body('ingredients').isArray({ min: 0 });
// Verifies that team_members is an array with length >= 0 and <= 10
check('team_members').isArray({ min: 0, max: 10 });
isObject(options?: { strict?: boolean }): ValidationChain
ํ๋ ๊ฐ์ด ๊ฐ์ฒด์ธ์ง ํ์ธํ๋ ๊ฒ์ฆ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ค. ์๋ฅผ ๋ค์ด {}
, { foo: 'bar'}
, new MyCustomClass()
๋ ์ด ๊ฒ์ฆ๊ธฐ๋ฅผ ํต๊ณผํ๋ค.
strict
์ต์
์ false
๋ก ์ค์ ํ๋ฉด pure Javascript์
typeof value === 'object'
(javascript์์ ๋ฐฐ์ด๊ณผ null
์ typeof ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์
์ ํ์ธํ๋ฉด object๋ก ๋์จ๋ค.)์ ๋์ผํ๊ฒ ์๋ํ๋ค.
isString(): ValidationChain
pure Javascript์ typeof value === 'string'
๊ณผ ๋์ผํ๊ฒ ๋์ํ๋ค.
notEmpty(): ValidationChain
๋น ๋ฌธ์์ด์ด ์๋์ง ํ์ธํ๋ ๊ฒ์ฆ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ค. .not().isEmpty()
์ ๋์ผํ๊ฒ ๋์ํ๋ค.
Standard validators ํ์ธ
guide Standard validators/sanitizers ํ์ธ
customSanitizer(sanitizer: (value, { req, location, path }) => any): ValidationChain
์ปค์คํ ์ ์ ๊ธฐ ํจ์๋ฅผ ์ฒด์ธ์ ์ถ๊ฐํ๋ค. ์ ์ ๊ธฐ๋ฅผ ๊ฑฐ์ณ ํ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ค.
app.post('/object/:id', param('id').customSanitizer((value, { req }) => {
// In this app, users have MongoDB style object IDs, everything else, numbers
return req.query.type === 'user' ? ObjectId(value) : Number(value);
})), (req, res) => {
// Handle request
});
default(defaultValue: any): ValidationChain
ํ๋ ๊ฐ์ด ๋น ๋ฌธ์์ด, null
, undefined
, NaN
์ผ ๊ฒฝ์ฐ defaultValue
๋ก ๋ณ๊ฒฝํ๋ค.
app.post('/', body('username').default('foo'), (req, res, next) => {
// 'bar' => 'bar'
// '' => 'foo'
// undefined => 'foo'
// null => 'foo'
// NaN => 'foo'
});
toArray(): ValidationChain
๋ฐฐ์ด๋ก ๋ณ๊ฒฝํ๋ค. ์ด๋ฏธ ๋ฐฐ์ด์ด๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ค. undefined
๊ฐ์ด๋ผ๋ฉด ๋น ๋ฐฐ์ด์ด ๋๋ค.
toLowerCase(): ValidationChain
toUpperCase(): ValidationChain
๋ฌธ์์ด์ ์๋ฌธ์๋ก ํน์ ๋๋ฌธ์๋ก ๋ณ๊ฒฝํ๋ค. ํ๋๊ฐ์ด ๋ฌธ์์ด์ด ์๋๋ผ๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ค.
Standard sanitizers ํ์ธ
guide Standard validators/sanitizers ํ์ธ
bail(options?: { level: 'chain' | 'request' }): ValidationChain
ํ๋ผ๋ฏธํฐ options.level
์ ๊ธฐ๋ณธ๊ฐ์ chain
์ด๋ค.
request
๋ก ์ค์ ํ๋ฉด ์ด์ ๊ฒ์ฆ๊ธฐ ์ค ํ๋๋ผ๋ ์คํจํ ๊ฒฝ์ฐ validation chain ์คํ์ด ๋ฉ์ถ๋ค.
์คํจ ์ .bail({level:'request'})
์ดํ์ ๊ฒ์ฆ๊ธฐ๋ ์คํ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ด ๋ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ธ๋ถ API๋ฅผ ์ฌ์ฉํ๋ ์ปค์คํ
๊ฒ์ฆ๊ธฐ๊ฐ ์คํ๋๋ ๊ฒ์ ๋ฐฉ์งํ ๋ ์ ์ฉํ๋ค.
.bail()
์ ๊ฐ์ validation ์ฒด์ธ์์ ์ฌ๋ฌ๋ฒ ์ฌ์ฉํ ์ ์๋ค.
body('username')
.isEmail()
// If not an email, stop here
.bail()
.custom(checkDenylistDomain)
// If domain is not allowed, don't go check if it already exists
.bail()
.custom(checkEmailExists);
app.get(
'/search',
query('query').notEmpty().bail({ level: 'request' }),
// If `query` is empty, then the following validation chains won't run:
query('query_type').isIn(['user', 'posts']),
query('num_results').isInt(),
(req, res) => {
// Handle request
},
);
๐จoneOf()
์ checkExact()
๋ฅผ ์ฌ์ฉํ ๋ request-level bail์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ณ๋ ฌ๋ก ์คํ๋๋ validation chains๊ฐ ์์ฐจ์ ์ผ๋ก ์คํ๋์ด์ผ ํด์ ์คํ์ด ๋๋ ค์ง ์ ์๋ค.
if(condition: CustomValidator | ContextRunner): ValidationChain
์ด ํ๋์ ๋ํด validation chain์ด ๊ณ์ ์คํ๋์ด์ผ ํ๋์ง ์๋์ง ์กฐ๊ฑด์ ์ถ๊ฐํ๋ค.
์กฐ๊ฑด์ ์ปค์คํ ๊ฒ์ฆ๊ธฐ ํน์ contextRunner ์ธ์คํด์ค์ผ ์ ์๋ค.
body('newPassword')
// Only validate if the old password has been provided
.if((value, { req }) => req.body.oldPassword)
// Or, use a validation chain instead
.if(body('oldPassword').notEmpty())
// The length of the new password will only be checked if `oldPassword` is provided.
.isLength({ min: 6 });
not(): ValidationChain
์ฒด์ธ ๋ด์ ์๋ ๋ค์ ๊ฒ์ฆ๊ธฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ถ์ ํ๋ค.
check('weekday').not().isIn(['sunday', 'saturday']);
optional(options?: boolean | {
values?: 'undefined' | 'null' | 'falsy',
nullable?: boolean,
checkFalsy?: boolean,
}): ValidationChain
ํ์ฌ validation chain์ ์ ํ์ฌํญ์ผ๋ก ํ์ํ๋ค.
optional ํ๋๋ value์ ๋ฐ๋ผ ๊ฒ์ฆ์ ๊ฑด๋๋ด๋ค.
์ด๋ค ๊ฐ์ด optinal๋ก ๊ฐ์ฃผ๋๋์ง๋ options.values
์ ๋ฐ๋ผ ๋ค๋ฅด๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก undefined๋ก ์ค์ ๋๋ค.
options.values | behavior |
---|---|
undefined | ํ๋ ๊ฐ์ด undefined ๋ผ๋ฉด optional๋ก ๊ฐ์ฃผ๋๋ค. |
null | ํ๋ ๊ฐ์ด undefined๋ null์ด๋ฉด optional๋ก ๊ฐ์ฃผ๋๋ค. |
falsy | ํ๋ ๊ฐ์ด falsy ๊ฐ(๋น ๋ฌธ์์ด 0, false, null, undefined)์ด๋ฉด optionaly๋ก ๊ฐ์ฃผ๋๋ค. |
nullable
, checkFalsy
๋ deprecated๋ค. options.values
๋ฅผ null
ํน์ falsy
๋ก ์ค์ ํด์ ์ฌ์ฉํ๋ผ
๐จvaildator์ nasitizer์ ๋ฌ๋ฆฌ .optional()
์ ์์น์ ์๊ด์์ด ๊ฐ์ด ํด์๋๋ ๋ฐฉ์์ ์ํฅ์ ์ค๋ค. ์ฆ, ์ฒด์ธ ์ด๋์์ ๋ฐ์ํ๋๋ผ๋ ์ํฅ์ ์ค๋ค.
body('json_string').isLength({ max: 100 }).isJSON().optional().
body('json_string').optional().isLength({ max: 100 }).isJSON().
๋์ ์ฐจ์ด๋ ์๋ค.
withMessage(message: any): ValidationChain
์ด์ ๊ฒ์ฆ๊ธฐ์ ์ํด ์ฌ์ฉ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ค์ ํ๋ค.
import { ExpressValidator } from 'express-validator';
new ExpressValidator(
customValidators?: Record<string, CustomValidator>,
customSanitizers?: Record<string, CustomSanitizer>,
options?: {
errorFormatter: ErrorFormatter<E>;
}
);
ExpressValidator
๋ express-validator API๋ฅผ ๋ํํ ํด๋์ค๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ ์ฐจ์ด์ ์ด ์๋ค.
์ฌ์ฉ์ ์ ์ ๊ฒ์ฆ๊ธฐ ๋ฐ ์ ์ ๊ธฐ" ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ
.errorFormatter๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ, .validationResult()์ ์ฌ์ฉ๋๋ ๊ธฐ๋ณธ ์ค๋ฅ ํฌ๋งคํฐ๋ก ์ฌ์ฉ๋๋ค.
๋์ค์ ๋ฒ์ญ
import { matchedData } from 'express-validator';
matchedData(req, options?: {
includeOptionals?: boolean,
onlyValidData?: boolean,
locations?: Location[],
})
express-validator๋ก ๊ฒ์ฆ ๋ฐ ์ ์ ๋ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๊ณ , ๊ทธ ๋ฐ์ดํฐ๊ฐ ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
app.post(
'/contact-us',
[body('email').isEmail(), body('message').notEmpty(), body('phone').optional().isMobilePhone()],
(req, res) => {
const result = validationResult(req);
if (!result.isEmpty()) {
// handle validation errors
return res.send('Please fix the request');
}
const data = matchedData(req);
// If phone isn't set:
// => { email: 'foo@bar.com', message: 'Hi hello' }
// If phone is set:
// => { email: 'foo@bar.com', message: 'Hi hello', phone: '+1223334444' }
},
);
๊ธฐ๋ณธ์ ์ผ๋ก matchedData
๋ optional์ด๊ฑฐ๋ request์ ํฌํจ๋์ง ์์ ๋ฐ์ดํฐ๋ ๋ฐํ ๊ฐ์ฒด์ ๋ด์ง ์๋๋ค.
์ด ๋์์ ๋ณ๊ฒฝํ๋ ค๋ฉด options.includeOptionals
์ true๋ก ์ค์ ํ๋ค.
app.post(
'/contact-us',
[body('email').isEmail(), body('message').notEmpty(), body('phone').optional().isMobilePhone()],
(req, res) => {
const data = matchedData(req, { includeOptionals: true });
// If phone isn't set:
// => { email: 'foo@bar.com', message: 'Hi hello', phone: undefined }
},
);
๊ธฐ๋ณธ์ ์ผ๋ก matchedData
๋ ์ ํจํ ๋ฐ์ดํฐ๋ง ๋ฐํํ๋ค. ์์ฒญ์ ์ ํจํ์ง ์์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ๋ฐํ ๊ฐ์ฒด์ ๋ด์ง ์๋๋ค.
์ด ๋์์ ๋ณ๊ฒฝํ๋ ค๋ณ options.onlyValidData
๋ฅผ false๋ก ์ค์ ํ๋ค.
app.post('/signup', body('email').isEmail(), body('password').notEmpty(), (req, res) => {
const data = matchedData(req, { onlyValidData: false });
// => { email: 'not_actually_an_email', password: '' }
});
๊ธฐ๋ณธ์ ์ผ๋ก matchedData
๋ ๊ฒ์ฆ์ ํต๊ณผํ request์ ๋ชจ๋ locations์ ๋ฐ์ดํฐ๋ฅผ ๊ฒฐ๊ณผ ๊ฐ์ฒด์ ๋ด์ ๋ฐํํ๋ค.
์ด ๋์์ ์์ ํ๋ ค๋ฉด options.locations
๋ฅผ ์์ ํ๋ค. options.locations
๋ฅผ ๋ฆฌ์คํธ๋ก ์ค์ ํ๊ณ ํด๋น locations์ ์ํ ๋ฐ์ดํฐ๋ง ๊ฒฐ๊ณผ ๊ฐ์ฒด์ ๋ด๋๋ก ํ ์ ์๋ค.
app.post(
'/signup',
[body('email').isEmail(), body('password').notEmpty(), query('subscribe_newsletter').isBoolean()],
(req, res) => {
const data = matchedData(req);
// => { email: 'foo@bar.com', password: '12345', subscribe_newsletter: true }
const data2 = matchedData(req, { locations: ['query'] });
// => { subscribe_newsletter: true }
},
);
์์ฒญ์ด ์ ํจํ์ง, ๋ฐ์ ๊ฐ๋ฅํ ๊ฒ์ฆ ์๋ฌ๋ ๋ฌด์์ธ์ง ์ดํด๋ณด์.
validationResult(req: Request): Result<ValidationError>
request๋ก๋ถํฐ ๊ฒ์ฆ ๊ฒฐ๊ณผ๋ฅผ ์ถ์ถํ๋ค. ๊ฒ์ฆ ํ์๋ Result
๊ฐ์ฒด๋ก ๊ฒ์ฆ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๋ํํ๋ค.
const { query, validationResult } = require('express-validator');
app.post('/hello', query('person').notEmpty(), (req, res) => {
const result = validationResult(req);
// Use `result` to figure out if the request is valid or not
});
validationResult.withDefaults<T>(options: { formatter?: ErrorFormatter<T> }): ResultFactory<T>
validationResult()
์ ์ ์ฌํ ์๋ก์ด ํจ์๋ฅผ ์์ฑํ๋ค.
์์ฑ๋ ํจ์๋ ์ฃผ์ด์ง ์ต์
์ ๋ฐํ๋ Result
๊ฐ์ฒด์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค.
์๋ฅผ ๋ค์ด, ๊ฒฐ๊ณผ์ ๊ธฐ๋ณธ ์ค๋ฅ ํฌ๋งทํฐ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ ์ ์๋ค.
const { query, validationResult } = require('express-validator');
const myValidationResult = validationResult.withDefaults({
formatter: error => error.msg,
});
app.post('/hello', query('person').notEmpty(), (req, res) => {
const errors = myValidationResult(req).array();
// => ['Invalid value']
});
๊ฒฐ๊ณผ ๊ฐ์ฒด๋ ์์ฒญ์ ์ํ๋ฅผ ๋๋ฌ์ผ ๋ํผ๋ค. ๊ฒฐ๊ณผ ๊ฐ์ฒด๋ ์์ฒญ์ด ์ ํจํ์ง ํ๋จํ ์ ์๋ ๋ช ๊ฐ์ง ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
๐จํ์ ๋งค๊ฐ ๋ณ์ T๋ .array() ๋ฐ .mapped()์ ๊ฐ์ ๋ฉ์๋์์ ๋ฐํ๋๋ ์ค๋ฅ์ ํ์ ์ ๋ํ๋ธ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ValidationError์ด๋ฉฐ, .formatWith()๋ฅผ ์ฌ์ฉํด์ ๋ณ๊ฒฝํ ์ ์๋ค.
isEmpty(): boolean
request๊ฐ ๊ฒ์ฆ ์๋ฌ๋ฅผ ํฌํจํ๋์ง ์๋์ง๋ฅผ ๋ฐํํ๋ค.
formatWith<T>(formatter: ErrorFormatter<T>): Result<T>
๊ฒ์ฆ ์ํ๋ฅผ ๋ค์ ๋๋ฌ์ผ ์๋ก์ด Result
๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ์๋ก์ด Result
๊ฐ์ฒด๋ ์ฃผ์ด์ง formatter
๋ฅผ ์๋ฌ ํฌ๋งคํฐ๋ก ์ฌ์ฉํ๋ค.
const { query, validationResult } = require('express-validator');
app.post('/hello', query('person').notEmpty(), (req, res) => {
const result = validationResult(req);
const errors = result.array();
// => [{ msg: 'Invalid value', ... }]
const result2 = result.formatWith(error => error.msg);
const errors2 = result2.array();
// => ['Invalid value']
});
array(options?: { onlyFirstError?: boolean }): T[]
๊ฒ์ฆ๋ ๋ชจ๋ ํ๋๋ก๋ถํฐ ๋ฐ์๋ ๋ชจ๋ ์๋ฌ๋ฅผ ๋ฆฌ์คํธ๋ก ๋ง๋ค์ด ๋ฐํํ๋ค.
const result = validationResult(req).array();
// => [{ msg: 'Invalid value', path: 'field1' }, { msg: 'Invalid value', path: 'field1' }]
options.onlyFirstError
๊ฐ true
๋ก ์ธํ
๋๋ฉด ๊ฐ ํ๋์ ์ฒซ ๋ฒ์งธ ์๋ฌ๋ง ๋ฐํํ๋ค.
const result = validationResult(req).array({ onlyFirstError: true });
// => [{ msg: 'Invalid value', path: 'field1' }]
mapped(): Record<string, T>
ํ๋์ ๋ฐ์ํ ์๋ฌ๋ฅผ ๋งคํํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ํ๋๋ก๋ถํฐ ๋ฐ์ํ ์๋ฌ๊ฐ ์ฌ๋ฌ ๊ฐ๋ผ๋ฉด ์ฒซ ๋ฒ์งธ ์๋ฌ๋ง ๋ฐํํ๋ค.
const result = validationResult(req).mapped();
// => { field1: { msg: 'Invalid value', ... }, field2: { msg: 'Invalid value', ... } }
throw(): void
๊ฒฐ๊ณผ ๊ฐ์ฒด๊ฐ ์๋ฌ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ์ด ๋ฉ์๋๋ Result ํ์ ๊ณผ ๋์ผํ ๋ฉ์๋๋ก ์ฅ์๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค.(this method throws an error decorated with the same methods as the Result type.)
๋ง์ฝ ๊ฒฐ๊ณผ ๊ฐ์ฒด์ ์๋ฌ๊ฐ ์๋ค๋ฉด ์ด ๋ฉ์๋๋ ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ค.
app.post('/hello', query('person').notEmpty(), (req, res) => {
try {
validationResult(req).throw();
res.send(`Hello, ${req.query.person}!`);
} catch (e) {
res.status(400).send({ errors: e.mapped() });
}
});
express-validator์ ๋ค์ํ API๋ ์๋ก ๋ค๋ฅธ ์ข ๋ฅ์ ๊ฒ์ฆ ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค.
type FieldValidationError = {
type: 'field';
location: Location;
path: string;
value: any;
msg: any;
};
๋จ์ผ ํ๋ ๊ฒ์ฆ์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ํ๋ธ๋ค.
type AlternativeValidationError = {
type: 'alternative';
msg: any;
nestedErrors: FieldValidationError[];
};
์ฌ์ฉํ ์ ์๋ ๋ชจ๋ ๊ฒ์ฆ ์์
(ex. in oneOf()
)์์ ์คํจํ์ ๋ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ํ๋ธ๋ค. nestedErrors์๋ ๊ฐ๋ณ ํ๋ ์ค๋ฅ์ flat list๊ฐ ํฌํจ๋๋ค.
๋ชจ๋ ๋์ฒด ๋ฐฉ๋ฒ(ex. in oneOf()
)์ด ์ ํจํ์ง ์์์ ๋ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ํ๋
๋๋ค. nestedErrors์๋ ๋์ฒด ๋ฐฉ๋ฒ๋ณ๋ก ๊ทธ๋ฃนํ๋ ๊ฐ๋ณ ํ๋ ์ค๋ฅ ๋ชฉ๋ก์ด ํฌํจ๋ฉ๋๋ค.
type UnknownFieldsError = {
type: 'unknown_fields';
msg: any;
fields: { path: string; location: Location; value: any }[];
};
ํ๋ ์ด์์ ํ๋๊ฐ unknown ํ๋์ผ ๋ ๋ฐ์ํ๋ ์๋ฌ๋ฅผ ๋ํ๋ธ๋ค.
์ฆ, checkExact()
๊ฐ ์คํ๋ ๋ ๊ฒ์ฆ ์ฒด์ธ์ด ์๋ ๊ฒฝ์ฐ์ด๋ค.
fields
์๋ ๋ชจ๋ unknown ํ๋๋ค์ ๊ฒฝ๋ก์ locations, values ๋ค์ด์๋ ๋ฆฌ์คํธ๋ค ๋ฐํํ๋ค.
์ด๋ ํ ๊ฒ์ฆ ์ค๋ฅ๋ ๋ฐ์ํ ์ ์๋ค. type ์์ฑ์ ์ดํด๋ณด๋ฉด ์ค์ ๋ก ๋ฐ์ํ ์ค๋ฅ๊ฐ ๋ฌด์์ธ์ง ํ์ธํ ์ ์๋ค.
switch (error.type) {
case 'field':
// `error` is a `FieldValidationError`
console.log(error.path, error.location, error.value);
break;
case 'alternative':
// `error` is an `AlternativeValidationError`
console.log(error.nestedErrors);
break;
case 'alternative_grouped':
// `error` is a `GroupedAlternativeValidationError`
error.nestedErrors.forEach((nestedErrors, i) => {
console.log(`Errors from chain ${i}:`);
console.log(nestedErrors);
});
break;
case 'unknown_fields':
// `error` is an `UnknownFieldsError`
console.log(error.fields);
break;
default:
// Error is not any of the known types! Do something else.
throw new Error(`Unknown error type ${error.type}`);
}
type ErrorFormatter<T> = (error: ValidationError) => T;
Result#mapped()
๋ฐ Result#array()
์ ๊ฐ์ ๋ฉ์๋์์ ๋ฐํ๋ ์ค๋ฅ๋ฅผ ํฌ๋งทํ๋ ๋ฐ ์ฌ์ฉ๋๋ ํจ์๋ค.
์ด ํจ์๋ ํฌ๋งท๋์ง ์์ ์ค๋ฅ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ก์ด ๊ฐ์ ๋ฐํํด์ผ ํ๋ค.