프로그래밍 기초

MVC 패턴에서의 validation 처리

hs-archive 2023. 9. 10. 17:09

Validation

validation(유효성 검사)은 데이터가 정확하고 유용한지 확인하는 프로세스입니다. 예를 들어, 함수의 매개 변수가 해당 함수의 로직을 수행하기에 적합한지 확인하는 것입니다.

 

MVC 패턴을 사용하는 server-side에서 이러한 Validation은 어디에서 수행해야 할까요?

 

MVC 패턴과 Validation

우선 controller에서 모든 validation을 처리하는 구조를 생각해 봅시다.

 

이 형태에서는 service는 무조건 controller로부터 호출되어야 합니다. 왜냐하면 controller에서 모든 validation을 처리하기 때문입니다. 만약, controller가 아닌 다른 곳에서 service를 호출한다면 service로 넘어간 파라미터는 validation을 확인하지 않은 데이터가 됩니다. 앞서 말씀드렸듯 controller에서 모든 validation을 처리하는 구조에서는 controller에서만 service를 호출해야 하는데, 실제 프로젝트에서는 service가 다른 service를 호출하는 코드가 빈번하게 작성됩니다. 그러므로, controller에서 모든 validation을 처리하는 구조는 그다지 올바르게 느껴지지 않습니다.

 

그러면 validation을 어디에서 처리해야 할까요? 아래처럼 모든 controller, service, repository에서 동일한 validation을 중복으로 처리해야 할까요?

// controller
class controller {
    validation(data);
    call service;
}


// service
class Service {
    validation(data);
    call repository;
}


// repository
class Repository {
    validation(data);
    call DB;
}

 

하지만 위와 같은 방식은 너무 중복이 많습니다.

 

생각해 보면 controller, service, repository는 역할과 책임에 따라 나눈 레이어들입니다. 따라서, 해당 레이어의 역할과 책임에 맞는 validation을 수행하는 것이 controller, service, repository 패턴에서 validation을 처리하는 좋은 방법이라고 생각합니다.

 

Controller Layer의 validation 

controller layer는 아래와 같은 역할을 담당합니다.

  1. client의 request를 받아

  2. "request에 담긴 데이터를 매개 변수로 사용"하여 service를 호출하고

  3. service가 반환한 값을 client에게 전달

 

controller의 역할은 다양하지만 중요한 것은 request에 담긴 데이터를 매개 변수로 사용하여 service를 호출하는 것입니다. controller는 service에게 넘겨준 데이터를 service에서 어떻게 처리할지 모릅니다. (controller는 service의 내부 로직을 모른다는 것) controller가 아는 것은 오로지 service에게 넘겨줘야 하는 데이터의 "형태"입니다. 따라서 controller layer에서 수행되는 validation은 "client가 보낸 request에 담긴 데이터가 service에게 넘겨주기에 올바른 형태인가?"를 검사해야 합니다.

 

class User {
    email: String;
    age: number;
}

userService {
    someMethod(parameter: User) {
    	...
    }
}

예를 들어, 위와 같이 userService가 있을 때 userService의 someMethod의 매개변수는 User 타입이어야 합니다. 따라서 client가 보낸 "request에 담긴 데이터가 User 타입과 동일한지 확인하는 것"이 controller layer에서 수행되어야 할 validation입니다.

 

// requestData
{
    "email": "hs@gmail.com",
    "age": 123,
}

이러한 데이터를 담은 request가 온다면 해당 데이터는 User 형식과 동일하기 때문에 이는 유효한 요청입니다. 따라서 someMethod()를 호출하여 로직을 계속 진행합니다.

 

// requestData
{
    "email": "hs@",
    "age": 123
}

이러한 데이터를 담은 request가 온다면 해당 데이터는 User 형식과 동일하지만, email의 경우 유효한 email이라고 할 수 없습니다. (xxx@xx.xxx 형식이 아님) 이는 유효하지 않은 요청입니다. 따라서 이후의 로직을 진행하지 않습니다. (보통 알맞은 Error를 발생시킵니다.)

 

Service Layer의 validation 

service layer는 아래와 같은 역할을 담당합니다.

  1. 전달받은 매개변수를 가지고 "비즈니스 로직을 수행"합니다.

      - 이때 보통 repository를 호출합니다.

      - repository를 호출할 때 적절한 매개변수를 담아 호출합니다.

  2. 비즈니스 로직의 수행 결과를 반환합니다.

 

비즈니스 로직이란 해당 애플리케이션에서 통용되는 논리를 말합니다. 예를 들어, 이미 가입되어 있는 이메일로는 회원 가입을 하지 못한다던가, 아이디에는 욕설이 들어가면 안 된다던가 하는 것입니다. 이러한 조건을 문제없이 통과하면 repository를 호출하여 해당 데이터를 DB에 저장할 것입니다.

 

service의 역할은 다양하지만 중요한 것은 "비즈니스 로직 수행" 입니다. 따라서 service layer에서 수행되는 validation은 "전달받은 매개 변수가 비즈니스 로직을 수행하기에 적절한 데이터인가?"를 검사해야 합니다.

// e.g., 이미 가입되어 있는 이메일로는 회원 가입이 불가할 때 ...
		
signup(user: User) {
    // Validation 수행
    checkUserEmailValidation(user);

    // 유효성이 확인 되었으니 이후 로직 수행...
}

checkUserEmailValidation(user: User) {
    // 전달받은 매개 변수(user)가 갖고있는 email을 통해
    // DB에 동일한 email을 갖는 기존 유저가 있는지 확인
    const registeredUser = userRepository.getUserByEmail(user.email);

    // 만약 동일한 email을 갖는 기존 유저가 있다면
    // error를 throw함
    if (registeredUser) {
        throw new Error();
    }		
}

 

Repository Layer의 Validation

repository layer는 아래와 같은 역할을 담당합니다.

  1. 전달받은 매개변수를 가지고 DB로 쿼리를 날립니다.

  2. 질의의 결과를 반환합니다.

 

repository의 역할은 외부 인프라와의 직접적인 소통입니다. 따라서 repository layer에서 수행되는 validation은 "전달받은 매개 변수가 외부 인프라와 소통하기에 적절한 값을 갖는가?"를 검사해야 합니다.

 

예를 들어, SQL Injection을 막기 위해여 espace()를 수행하던가 placeholder를 사용하여 쿼리를 작성하는 작업이 이에 해당됩니다.

// placeholder를 사용하여
// SQL Injection을 방지
db.query("SELECT * FROM user WHERE email = ?", [user.email])

 

결론

MVP 패턴에서 각 레이어를 나눈 기준에 따라 Validation을 진행하는 구조에 대해 알아보았습니다. 다만, validation를 처리하는 위치는 적절하게 바뀔 수 있으며, 여러 가지 기준이 있을 수 있습니다.

 

 

 

 

 


https://blog.barogo.io/%EA%B0%9C%EB%B0%9C%EC%9D%B8%ED%84%B4-validation%EC%9D%98-%EC%A0%81%EC%A0%88%EC%84%B1-79ed23f28a72?gi=d2ba6bf2fe79 

 

[개발인턴] Validation의 적절성

안녕하세요. R&D 개발 그룹 인턴 강소라입니다. 지금까지 Validation을 생각하며 코드를 작성한 적이 있었던가? Validation 자체에 대해 고민해 본 적이 있는가? 돌아보면, input값이 들어왔는지 확인하

blog.barogo.io

https://velog.io/@rmswjdtn/Spring-Validation%EC%9D%80-%EC%96%B4%EB%94%94%EC%84%9C-%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C

 

[Spring] Validation은 어디서 해야할까?

하나의 작은 프로젝트(?)를 만들다 보면 슬슬 고민이 되는 부분 바로 유효성검사이다! 크게 Controller, Service, Repository, Entity(model)로 나눠서 작업하는 경우가 많은데 그렇다면 요청에서 넘어온 값들

velog.io

 

'프로그래밍 기초' 카테고리의 다른 글

statement와 expression / literal과 variable, constant  (0) 2023.09.08
Node.js 이벤트 루프  (0) 2023.09.04
AWS S3에 파일 업로드: pre-signed URL  (0) 2023.08.28
GraphQL 맛보기  (0) 2023.08.24
SOLID 원칙  (0) 2023.08.17