이전에 진행한 프로젝트에 유효성을 검증하는 기능을 넣으려고 했다.
하나하나 조건문을 이용해 검증하기에는 코드도 지저분해지고 미들웨어로 넣어 처리해주고 싶었다.
그래서 joi라는 것을 사용해 유효성 검증 기능을 넣었다.
joi 왜에도 node.js 환경에서 유효성 검증을 도와주는 모듈은 다양하다.
express-validator, yup 등이 있지만 정확한 차이는 잘 모르겠고 이용 수가 가장 많으면서 스키마로 따로 정의할 수 있다는 저에서 joi를 선택했다.
모듈을 설치
$ yarn add joi
사용법은 간단했다.
내가 작성한 코드를 간단하게 얘기하자면
유효성 검증을 위한 조건을 가진 스키마들을 따로 정의하고 요청과 함께 들어온 데이터들을 스키마와 비교해 검사하는 미들웨어를 따로 작성했다. 그 후 각각 Router에 미들웨어를 추가해주는 방식으로 코드를 적었다.
스키마 작성
// validators/userValidator.js
import joi from 'joi';
const registerScema = joi.object({
nickname: joi.string().required(),
email: joi.string().email().required(),
password: joi.string().min(4).required(),
sex: joi.string().valid('male', 'female').required(),
birth:joi.date().required(),
interest: joi.number().integer().min(1).min(5).required(),
likeType: joi.string().valid(
'노말',
'불꽃',
'물',
'풀',
'전기',
'얼음',
'격투',
'독',
'땅',
'비행',
'에스퍼',
'벌레',
'바위',
'고스트',
'드래곤',
'강철',
'페어리'
).required(),
})
...
export { registerScema, ... }
원래는 Router의 미들웨어 작성 부분에서 같이 끼어 넣어줘도 되고 아니면 비즈니스 로직 내에서도 작성해 검증이 가능하다. 하지만 저 긴 코드가 껴 들어가게 되면 지저분해질 거 같아 난 따로 적어준 거다.
각각 요소마다 Type과 Required, 길이, 범위, enum 등의 조건을 넣어 줄 수 있다.
사용 가능한 조건들은 매우 많으니 공식문서에서 확인하면 좋을 거 같다.
이후 나중에 확장성을 고려해 "index.js"에서 re-export를 해줬다.
// validators/index.js
import {registerScema, ...} from './userValidator'
export{registerScema, ...}
validation middleware 작성
요청과 함께 들어오는 데이터를 스키마와 비교해주는 미들웨어를 작성해준다.
이곳에서는 req.body에 있는 데이터와 내가 작성한 스키마의 조건을 비교한 후, 맞지 않다면 그에 준하는 message를 작성해 클라이언트에게 반환해주고 조건에 맞다면 다음 미들웨어, 혹은 비즈니스 로직으로 데이터를 넘겨준다.
// middlewares/validator.js
import createHttpError from 'http-errors'
//* Include all validators
const validators = require('../validators')
const validator = (validator) => {
//! If validator is not exist, throw err
if(!validators.hasOwnProperty(validator))
throw new Error(`'${validator}' validator is not exist`)
return async function(req, res, next) {
try {
const validated = await validators[validator].validateAsync(req.body)
req.body = validated
next()
} catch (err) {
//* Pass err to next
//! If validation error occurs call next with HTTP 422. Otherwise HTTP 500
if(err.isJoi)
return next(createHttpError(422, {message: err.message}))
next(createHttpError(500))
}
}
}
export { validator }
Router에 validator middleware 추가
// routers/userRouter.js
import { Router } from 'express';
import { userAuthService } from '../services/userService';
import { validator } from '../middlewares/validator'
const userAuthRouter = Router();
userAuthRouter.post('/user/register',validator('registerScema'), async function (req, res, next) {
try {
// {회원가입 작업}
} catch (error) {
next(error);
}
});
export { userAuthRouter };
난 위와 같이 넣어서 사용했다. 이제 끝이다. 테스트를 해보자
확인
express를 로컬 환경에서 실행한 후 회원가입을 시도하면 위와 같이 성공한 것을 알 수 있다.
이제 유효성 검사에서 위배되는 데이터를 넣어서 다시 시도해보자.
password를 두 글자로 변경해 시도하니 성공이 아닌 실패의 원인을 메시지로 보여준다.
다른 것도 해보자.
likeType을 enum 목록에 없는 '키보드'를 넣어주니 마찬가지로 메시지를 준다.
유효성 검사를 도와주는 모듈들은 정말 편리한 것 같다. 굳이 if 문 같은 조건문을 써가면서 하드코딩으로 검사를 안 해줘도 된다. 물론 front 레벨에서 사전에 검증을 다 하지만 보안상의 이유로 백엔드 레벨에서도 검증을 해주는 것은 당연하다고 한다. express를 사용하면서 잊기도 했고 좀 귀찮은 면이 있었는데 이번에 Nest.JS를 공부하면서 TypeScript와 dto를 계속 사용 보다 보니 익숙해지는 것 같다. 당연하게 생각하고 습관을 들여야겠다.
'Backend > Node.js' 카테고리의 다른 글
[TypeORM] Active Record Pattern과 Data Mapper Pattern (0) | 2022.09.15 |
---|---|
[WEB] Polling과 WebSocket (... socket.io) (0) | 2022.08.20 |
[Express] swagger를 router에서 분리 정리 (0) | 2022.07.22 |
[NestJS] JWT를 이용해 토큰 생성 (0) | 2022.07.19 |
[NestJS] Pipe를 이용한 유효성 검사 (0) | 2022.07.17 |