유효성검사를 모듈을 사용해서 하는 방법이 있다니 새롭다. 노드에서 제공하는 express-validator 미들웨어가 바로 그 주인공인데 익혀두면 많이 유용할 것 같다.
유효성 검사
validation
- 사용자가 입력한 값에 대한 유효성(=타당성)을 확인하는 것
- userId : 값 있어야, 숫자
- 사람 name : 숫자 x, 문자열, 2자 이상 ...
외부 모듈 "express-validator"
- 설치 : npm install express-validator
- 참조 링크 : https://express-validator.github.io/docs/guides/getting-started
Getting Started | express-validator
One of the best ways to learn something is by example!
express-validator.github.io
express-validator는 다양한 요청 데이터에 대한 유효성 검사를 제공한다.
- check
가장 일반적인 유효성 검사 함수이다. 이 메소드는 요청 객체의 어떤 부분이든 검사할 수 있다.
- body
: HTTP 요청의 body 부분에서만 작동한다. 요청된 바디에 text가 있고, text에 대한 유효성을 검사하고 싶으면 body('text')를 사용하면 된다.
- param
: url의 경로 매개변수를 검사하는 데 사용된다. 예를 들어, /user/:id와 같은 url에서 id 매개변수의 유효성 검사를 하려면 param('id')를 사용하면 된다.
- query
: url의 특정 쿼리 문자열에서 유효성 검사를 한다. 예를 들어, /search?query=something의 query 유효성 검사를 진행하고 싶다면, query('query')를 사용하면 된다.
- headers
: 이 메소드는 헤더에서 유효성 검사를 한다. 예를 들어, 컨텐츠 유형, 인증 정보 등을 포함할 수 있다. header('Authorization')은 Authorization에 대한 유효성 검사를 한다.
validator 사용법 - userId/name 유효성 검사
- 모듈 셋팅
- const {요청 데이터, 에러 시 결과값} = require('express-validator')
- api 메소드의 두번째 인자에 위치(배열 가능)
- post('경로',유효성검사 코드,(req,res)=>{콜백내용})
- notEmpty() : 비어있지 않아야 함 / isInt() : 숫자여야 함 / withMessage('메세지') : 이를 어길 시 '메세지'를 array에 담음
// 모듈 셋팅
const {body, param, validationResult} = require('express-validator')
// 유효성검사 모듈(body: 요청 데이터, validationResult : 에러 시 결과값)
router
.route('/')
.post(
// validator한테 userId 검사해줘 명령
[body('userId').notEmpty().isInt().withMessage('숫자 입력 필요!'),
body('name').notEmpty().isString().withMessage('문자 입력 필요!')
]
, (req,res)=>{
const err = validationResult(req)
if(!err.isEmpty()){
// console.log(err.array())
// 리턴으로 if문 종료
return res.status(400).json(err.array())
}
- 유효성검사를 통과하지 못했을 때 에러 처리
- validationResult의 결과값을 err에 넣고 err에 값이 있으면 res.json으로 err.array()(배열형태)를 리턴해준다.
, (req,res)=>{
const err = validationResult(req)
if(!err.isEmpty()){
// console.log(err.array())
// 리턴으로 if문 종료
return res.status(400).json(err.array())
}

sql 에러(err) 처리
- sql문에서 에러가 나는 경우 콜백함수의 첫번째 인자인 err를 통해 무슨 에러가 났는지 err문을 받을 수 있다.
// INSERT 쿼리문
conn.query(sql, values,
function (err, results) {
if(err){
console.log(err)
return res.status(400).end()
}
res.status(201).json(results)
}
}
- 에러 내용
- 채널 테이블에 데이터를 넣을 때 FK인 user_id 에 회원 테이블에 없는 user_id값을 넣어 발생한 에러이다. FK 제약조건을 어겼다는 메세지가 출력된다.
Error: Cannot add or update a child row: a foreign key constraint fails (Youtube.channels, CONSTRAINT user_id FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION)
at Packet.asError (c:\devCourse\youtube-demo\node_modules\mysql2\lib\packets\packet.js:740:17)
at Query.execute (c:\devCourse\youtube-demo\node_modules\mysql2\lib\commands\command.js:29:26)
at Connection.handlePacket (c:\devCourse\youtube-demo\node_modules\mysql2\lib\base\connection.js:475:34)
at PacketParser.onPacket (c:\devCourse\youtube-demo\node_modules\mysql2\lib\base\connection.js:93:12)
at PacketParser.executeStart (c:\devCourse\youtube-demo\node_modules\mysql2\lib\packet_parser.js:75:16)
at Socket. (c:\devCourse\youtube-demo\node_modules\mysql2\lib\base\connection.js:100:25)
at Socket.emit (node:events:519:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
at Readable.push (node:internal/streams/readable:392:5) {
code: 'ER_NO_REFERENCED_ROW_2',
errno: 1452,
sqlState: '23000',
sqlMessage: 'Cannot add or update a child row: a foreign key constraint fails (Youtube.channels, CONSTRAINT user_id FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION)',
sql: 'INSERT INTO channels (channel_name, user_id)\n' +
" VALUES ('재밌는 채널', 50)"
}
채널 리팩토링 + API 우선순위
- 우선순위는 코드 순서임
- 에러 시 코드마다 배열 다 뜸
update 리팩토링
- validator로 param에서 가져온 id, body에서 가져온 name 유효성 검사
- 유효성검사 에러 처리
- values에 name과 id를 넣고 쿼리문 실행
- 에러 시 res 상태코드 400 받고 종료(end())
.put(
[param('id').notEmpty().withMessage('채널id 필요!'),
body('name').notEmpty().isString().withMessage('채널명 오류!')]
, (req,res)=>{
const err = validationResult(req)
if(!err.isEmpty()){
return res.status(400).json(err.array())
}
let {id} = req.params;
id = parseInt(id);
let {name} = req.body
let sql = `UPDATE channels SET channel_name = ? WHERE id = ?`
let values = [name, id]
// UPDATE 쿼리문
conn.query(sql, values,
function (err, results) {
if(err){
console.log(err)
return res.status(400).end()
}
// 업데이트 잘 되었는지 유효성 검사
if(results.affectedRows == 0){
return res.status(400).end()
}else{
res.status(200).json(results)
}
}
);
※ res.end()
- res.end()는 보내줄 아무 데이터도 없는데 response를 끝내고 싶을때 사용한다.
ex) res.status(400).end();
- 사실 이 메소드는 사용하지 않아도 된다. 보내줄 데이터가 없을때 사용한다고 하는데, 주로 예를 드는 것이 404 에러처리를 리턴해주어야 할때다.res.json을 쓰나 res.send()를 쓰나 응답을 종료해주는 역할을 하기 때문에 굳이 명시적으로 표시해줄 필요는 없다.
- 업데이트 잘 되었는지 유효성 검사
- id 등 값을 잘못 넣어 수정이 안 될 때가 있는데 이때, 어떤 에러에도 걸리지 않고 result를 잘 반환해준다.
- 이때, results에 affectedRows를 가져와 0이면 error 상태코드를 반환해주는 방식으로 에러처리를 해줄 수 있다.
// 업데이트 잘 되었는지 확인
if(results.affectedRows == 0){
return res.status(400).end()
}else{
res.status(200).json(results)
}
유효성검사 미들웨어 분리
공통적으로 작성해주는 유효성 검사 분리하기

- 모든 api 메소드에 콜백함수 안에 있는 유효성검사 에러 확인 코드를 공통으로 빼려 한다.
- 처음에는 공통 함수를 정의해 호출하려 했다.
// 공통 함수 정의
function validate(req, res) {
const err = validationResult(req)
if(!err.isEmpty()){
// 리턴으로 if문 종료
return res.status(400).json(err.array())
}
}
// 함수 사용
, (req,res)=>{
validate(req, res)
- 그런데 공통함수를 정의해서 호출하는 대신, 파일 내부의 함수를 모듈화(미들웨어화)해서 호출하면 훨씬 코드를 줄일 수 있어 편하다.
// 파일 내부 함수 모듈화 가능 - 미들웨어
const validate = (req, res) => {
const err = validationResult(req)
if(!err.isEmpty()){
// 리턴으로 if문 종료
return res.status(400).json(err.array())
}
}
- 사용법
- validate를 유효성검사코드 넣는 배열에 위치시킨다.

※ Express 라우터의 api 메서드 구조
Express에서는 라우터 핸들러를 실행하기 전에 여러 개의 미들웨어를 순차적으로 실행할 수 있게 설계되어 있다.
예를 들어 .get() 은 (path, ...middleware, handler) 구조
<이슈>
validate 미들웨어 분리 시 error가 안났을 때 값을 안넘겨주므로 postman 무한대기 발생
next()
- validate 사용할 때 postman 실행 시 무한대기 발생 이슈 해결법
- 링크 : https://expressjs.com/en/5x/api.html#router.param
- 라우터 파라메터 중 하나로 다음 할 일로 넘기는 메소드
Express 5.x - API Reference
Access the API reference for Express.js 5.x, detailing all modules, methods, and properties for building web applications with this latest version.
expressjs.com


- router.param 중 하나인 next 를 넘겨 다음 할 일(미들웨어, 함수) 로 보내는 역할을 하는 next() 함수를 조건에 맞을 때 리턴해주면 된다.
express-validator는 처음 써보는데 매우 효율적이고 간단해 코드 줄이는 데 도움이 될 것 같다. 공통 함수를 미들웨어로 분리해 사용하는 방법 또한 코드를 경제적으로 쓰는 데 도움이 될만한 정보다. 문법에 익숙해져야겠다.
'데브코스 웹풀스택 과정 > TIL' 카테고리의 다른 글
| 1105 프로그래밍의 기본 원리 및 변수와 자료형 (0) | 2025.11.05 |
|---|---|
| 1002 쿠키와 세션 그리고 JWT(토큰 발행 및 쿠키담기, 유효기간 설정) (0) | 2025.10.02 |
| 0930 타임 존(timezone) 설정, 디비 연동 및 쿼리 가져오기 (0) | 2025.09.30 |
| 0929 MySQL (mariadb) 날짜/시간 타입, FK컬럼 추가, auto_increment (0) | 2025.09.29 |
| 0926 백엔드 심화 - DBMS(+3306 포트 사용하는 곳 검색) (1) | 2025.09.26 |