유효성 검사는 어디에서 처리해야하나?

·2021년 10월 13일
1
post-thumbnail

개발자 A씨 (FE) : 백앤드에서 처리해야겠지?
개발자 B씨 (BE) : 당연히 프론트에서 해야하는 거 아니야?




유효성 검사란?

유효성 검사는 데이터가 서버 혹은 데이터베이스로 옮겨지기 전, 개발자가 만든 조건에 부합하는지 확인, 검증하는 작업을 말합니다.

예를 들어 우리가 쿠팡에 새롭게 가입을 한다고 생각해봅시다. 가입 절차를 진행하다보면 우리가 자주 목격했던 글귀들을 목격하게 될 겁니다? "이미 가입된 ID 입니다." 혹은 "비밀번호는 영문,숫자,특수문자가 혼합되어야 합니다" 등 사용자는 개발자가 원하는 조건에 맞게 데이터를 입력해야만 가입절차를 완료할 수가 있습니다. 이러한 데이터 생성 작업들이 대부분 유효성 검사를 통해 이루어지는 것 입니다.




유효성 검사 시작하기

유효성 검사는 클라이언트, 서버 모두 처리가 가능합니다. 어느 쪽을 중점적으로 처리해야 하는지, 어떤 부분을 처리해야 하는지에 따라 개발자는 서버 측을 사용하기도, 클라이언트 측을 쓰기도 하죠. 유효성 검사에 대해 정해진 툴이 있는 것은 아니기 때문에 저 나름대로 습득한 방식을 이야기 해보려합니다.

클라이언트 측

클라이언트에서 일반적으로 가장 많이 사용되는 유효성 검사는 Form Validation 입니다. input 태그에 attributes 를 사용하여 submit 이벤트 실행 전 유효성 검사를 실행할 수 있습니다.

<!-- MDN 참조  -->
<form>
  <!-- required  -->
  <p>
    <fieldset>
      <legend>Do you have a driver's license?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>
      <input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>
      <input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</label>
    </fieldset>
  </p>
  <!-- 최소, 최대값 검증 -->
  <p>
    <label for="n1">How old are you?</label>
    <input type="number" min="12" max="120" step="1" id="n1" name="age"
           pattern="\d+">
  </p>
  <p>
    <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory" aria-label="required">*</abbr></label>
    <input type="text" id="t1" name="fruit" list="l1" required
           pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range">
    <datalist id="l1">
      <option>Banana</option>
      <option>Cherry</option>
      <option>Apple</option>
      <option>Strawberry</option>
      <option>Lemon</option>
      <option>Orange</option>
    </datalist>
  </p>
  <!-- 이메일 형식 검증 -->
  <p>
    <label for="t2">What's your e-mail address?</label>
    <input type="email" id="t2" name="email">
  </p>
  <p>
    <label for="t3">Leave a short message</label>
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
  </p>
  <p>
    <button>Submit</button>
  </p>
</form>

서버 측

서버의 경우에는 방식이 좀 더 다양합니다. route 에서 처리하거나, model 내에서 처리할 수 도 있으며, 필요한 경우라면 controller 에서 설정할 수도 있습니다. 선호하는 언어, 라이브러리에 따라 성능이나 방식은 다르기 마련입니다. 저의 경우에는node 를 자주 사용하므로 routemodel 에서 처리하였습니다.

route의 경우 'express-validator' 를 model은 'mongoose' 내장 validate 기능을, 
controller는 직접 custom 하였습니다. 
사이드 프로젝트의 10에 5 정도는 route를 사용했습니다. 빠르게 응답할 수 있고, 분류하기도 편하며, 코드가 좀 길어지긴 하지만 가독성도 괜찮기 때문입니다. 
// 유데미 수업 중 자료 참조
router.put(
  '/signup',
  [
    body('email')
      .isEmail() // 이메일 형식 검증
      .withMessage('Please enter a vaild email') // 에러 시 메시지 반환
      .custom((value, { req }) => {
        return User.findOne({ email: value }).then((userDoc) => {
          if (userDoc) {
            return Promise.reject('E-mail address already exists!');
          }
        });
      })
      .normalizeEmail(),
    body('password')
    .trim() // 문자열 맨앞뒤 빈공간 제거
    .isLength({ min: 5 }), // 최소값 설정
    body('name').trim().not().isEmpty(),
  ],
  authController.signup // 미들웨어를 통한 함수 실행. (유효성 검사 -> 이벤트)
);



어디에서 쓰는게 좋은가?

각 영역마다 장단점이 있습니다. 우선 처리 속도만 본다면 클라이언트가 압도적으로 빠를 수 밖에 없습니다. 렌더링 된 태그에는 이미 유효성 검사가 내장되어 있기 때문에 데이터 형식이 올바르지 않으면 서버까지 갈 필요도 없이 즉각적으로 유저에게 에러 메세지를 전달 할 수가 있습니다.

하지만 서버만 할 수 있는 유효성 검사들도 있습니다. 예를 들어 중복된 ID가 있는지 확인하기 위해서는 데이터 베이스 내의 가입된 ID 데이터를 탐색하는 작업을 진행해야 합니다. 이러한 경우는 클라이언트 유효성 검사에 비해 다소 시간이 걸릴지라도 반드시 필요한 부분이기 때문에 서버에서 작업해야하죠.




결론

서버에서 반드시 다루어야 하는 유효 검증이 있고, 클라이언트 측이 더욱 효과적인 유효 검증이 있습니다. 일반적으로 데이터 형식 email, password 길이, 나이 제한 등 을 다루는 작업은 클라이언트 내에서도 가능하고, 데이터 베이스를 의존해야 하는 작업들은 서버에서 다루는 것이 좋습니다.

물론 일반적이다는 것이지, 유효성 검사를 제어하는 영역은 어떤 프로젝트, 어떤 언어들을 사용하냐에 따라 쉽게 바뀔 수 있습니다. xss 혹은 custom http 와 같은 security 측면이나 브라우저 호환성 등을 생각한다면 서버 측면에 다루는 게 더 나을 겁니다. 서비스 지역과 서버의 거리가 매우 멀다면 서드파티 api 를 통해 클라이언트에서 처리하는 것이 오히려 옳은 방법이 될 수 있겠죠.

유효성 검사를 만드는데 정해진 정답 따위는 없습니다. 그럼에도 이러한 양면적인 측면들을 동시해 고려하면서 작업을 진행하는 것이 효과적인 유효성 검사를 만드는 첫 걸음이라 생각합니다.

profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글