코드이그나이터4 컨트롤러 다루기 - 8 - 유효성 검사하기

고은연·2021년 3월 11일
1

이번 챕터의 내용은 https://github.com/koeunyeon/ci4/tree/controller-validation 에서 코드를 확인하실 수 있습니다.

유효성 검사하기

웹 프로그래밍의 오랜 격언 중 하나는 "사용자의 입력은 믿지 말 것"입니다. 사용자가 굳이 악의가 있어서라기보다는 사용법이 익숙치 않아서, 혹은 재미로, 어떤 이유로든간에 개발자가 의도한 바와 다르게 작동시킨다는거죠.
그래서 우리는 유효성 검사가 필요합니다. 데이터가 원하지 않은 형식이나 값이 들어왔을 때 처리해야 합니다.


Sample 컨트롤러에 아래의 메소드를 추가합니다.

public function valid(){ // (1)
    $input = $this->validate([ // (2)
        "name" => [ // (3)
            'rules' => 'required|min_length[4]|max_length[10]', // (4)
            'errors' => [ // (5)
                'required' => '이름이 필요합니다',
                'min_length' => '이름은 최소 4글자 이상입니다.',
                'max_length' => '이름은 최대 10글자 이하입니다.'
            ]
        ],
        "age" => [ // (6)
            'rules' => 'required|is_natural|less_than[150]', // (7)
            'errors' => [ // (8)
                'required' => '필수값입니다', // (9)
                'is_natural' => "나이는 자연수여야 합니다.",
                'less_than' => "정말 150세 이상이신가요?"
            ]
        ]
    ]);
    
    if ($input){ // (10)
        return $this->response->setJSON("성공했습니다."); // (11)
    }else{
        $errors = $this->validator->getErrors();
        return // (12)
            $this
            ->response
            ->setStatusCode(400, "bad parameter") // (13)
            ->setJSON($errors);
    }
}

코드를 확인해 보겠습니다.
(1) 유효성 검사를 할 메소드 valid를 선언합니다.

(2) 코드이그나이터의 컨트롤러에서 유효성을 검사하기 위해서는 $this->validate 메소드를 사용합니다. 파라미터는 유효성 검사 규칙을 입력받습니다.
validate 메소드는 자동으로 요청 파라미터를 읽어서 유효성 검사 규칙에 맞는지 검사하는 역할을 합니다.
이 메소드는 부모 클래스인 BaseController에 정의되어 있습니다.
반환값은 성공/실패 여부를 나타내는 true 혹은 false입니다.

(3) 유효성 검사 규칙은 연관 배열로 이루어집니다. 연관배열의 키는 요청 파라미터의 키와 동일합니다.

(4) 개별 값을 검증하는 규칙은 "rules"를 키로, 규칙들을 |로 구분해서 나열합니다. 검증 규칙에 파라미터가 필요하다면 규칙 이름 뒤에 []로 전달합니다. 규칙은 공백이 없어야 합니다.

  • required : 반드시 값이 필요합니다. null, false, ""(빈 문자열), [](빈 배열)이면 실패합니다.
  • min_length : 값이 지정한 숫자보다 짧다면 실패합니다. min_length[4]는 문자열의 길이가 4보다 작다면 실패한다는 의미입니다.
  • max_length : 값이 지정한 숫자보다 길다면 실패합니다. max_length[10]은 문자열의 길이가 10보다 크다면 실패한다는 의미입니다.

(5) errors는 오류 메세지를 지정합니다. 키는 유효성 검사 규칙입니다.
'required' => '이름이 필요합니다'required 유효성 검사가 실패할 경우 보여질 오류 메세지를 '이름이 필요합니다.' 로 지정한다는 뜻입니다.
파라미터가 있는 유효성 검사 규칙일 경우 파라미터를 제외하고 규칙 이름만으로 오류 메세지 키를 지정해야 합니다. 따라서 'min_length[4]' => '이름은 최소 4글자 이상입니다.' 가 아니라 'min_length' => '이름은 최소 4글자 이상입니다.' 로 오류 메세지를 설정합니다.

(6) 검사할 파라미터의 키를 (3) 처럼 지정하면 됩니다.

(7) age에 대해 유효성 검사를 열거합니다. (4)name에 대해 유효성 검사 규칙을 열거한 것과 동일한 방법입니다.

(8) age에 대한 오류 메세지를 지정합니다. (5)name 에 대한 오류 메세지를 설정한 것과 같습니다.

(9) age에 각 항목에 대해 오류 메세지를 설정하는 부분입니다. name(5)에서 설정한 것과 같습니다.

(10) 컨트롤러에서 유효성 검사가 실패하면 $input 변수에 false가 담깁니다. 성공했을 경우 true가 됩니다.

(11) 성공한 경우 성공했다는 JSON을 클라이언트에 응답합니다.

(12) 실패했을 경우 HTTP STATUS CODE 400(Bad Request)와 함께 오류 메세지를 리턴합니다. 예제처럼 객체 하나의 메소드를 연속으로 호출하는 것을 메소드 체이닝이라고 부르는데, 객체를 만드는 패턴 중 하나입니다.

(13) 코드이그나이터4에서 응답 상태 코드를 설정하려면 response 객체에 setStatusCode 메소드를 사용하면 됩니다. 첫번째 파라미터는 상태 코드, 두번째 파라미터는 상태 메세지입니다. 두번째 파라미터는 옵셔널 파라미터여서 굳이 설정할 필요는 없지만, 메세지의 정확성을 나타내기 위해 추가적으로 선언했습니다.


이번에는 직접 HTML 폼을 만드는 대신, PHPStorm의 HTTP Request 기능을 이용해서 테스트해 보겠습니다. 간단하게 말하면 HTTP 요청을 브라우저에서 직접 하는 대신 미리 정의된 규칙을 통해 테스트하는 방법입니다.
VSCode를 쓰신다면 REST Client 플러그인을 쓰시면 되고, 그 외의 에디터는 POSTMAN 등을 이용해서 PHPStorm이 없이도 HTTP 클라이언트와 동일한 기능을 사용할 수 있습니다.

이 방법을 사용하면 URL과 요청 파라미터 등을 저장해놓고 사용할 수 있기 때문에 매 번 테스트할 때마다 손으로 직접 데이터를 입력하는 번거로움을 피할 수 있게 됩니다. 보통 데이터만 클라이언트와 교환하는 백엔드 개발에서 많이 사용하는 방법입니다.

PHPStorm탐색기에서 최상위 디렉토리인 sample을 선택한 후 rest_test 디렉토리를 생성합니다.
이후 sample/rest_test 디렉토리를 우클릭하고 New -> Http Request를 선택한 후 valid라고 입력해서 valid.http 파일을 생성합니다.

PHPStorm request 만들기 1
PHPStorm request 만들기 2

Add request 버튼을 클릭하고 POST Parameters body를 차례로 선택합니다. POST 요청을 보낼 수 있는 템플릿이 나옵니다.
PHPStorm request POST 템플릿

POST http://localhost:80/api/item
Content-Type: application/x-www-form-urlencoded

id=99&content=new-element

###

이제 템플릿의 내용을 아래와 같이 변경합니다.

###
# name required
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

age=30

변경된 부분은 테스트할 주소 http://localhost:80/api/item => http://localhost:8080/sample/valid 이고, HTTP 본문의 내용이 id=99&content=new-element => age=30로 변경되었습니다.

# 으로 시작하면 주석입니다. 이름 파라미터를 전달하지 않았을 경우 유효성 검사가 실행되는지 확인하는 용도입니다.

###은 각 요청을 구분합니다. 파일 하나에서 여러개의 요청을 동시에 할 수 있기 때문에 각 요청을 구분하는 구분자로 ###을 사용합니다.

첫번째 줄은 요청 메소드와 주소를 나타냅니다.

POST http://localhost:8080/sample/valid

첫번째 공백 이후 다음 공백까지는 HTTP 요청 헤더입니다. 예제에서는 Content-Type을 설정하는 용도로 사용했습니다.

Content-Type: application/x-www-form-urlencoded

공백이 나오고 나면 본문이 시작합니다. POST 파라미터도 GET 파라미터와 동일하게 &로 각 파라미터를 구분하고, 파라미터의 키와 값은 키=값 형태로 서버에 전달합니다.

age=30

테스트해 봅시다. 줄번호 옆의 초록색 오른쪽 화살표를 클릭한 후 Run on localhost:8080을 선택합니다.
아래 화면에 결과가 나오는 것을 확인할 수 있습니다.

PHPStorm rest client 결과

응답 내용을 살펴보겠습니다.

POST http://localhost:8080/sample/valid

HTTP/1.1 400 bad parameter
Host: localhost:8080
Date: Tue, 19 Jan 2021 12:38:26 GMT
Connection: close
X-Powered-By: PHP/7.4.8
Cache-control: no-store, max-age=0, no-cache
Content-Type: application/json; charset=UTF-8
Debugbar-Time: 1611059906
Debugbar-Link: http://localhost:8080/index.php/?debugbar_time=1611059906

{
  "name": "이름이 필요합니다"
}

Response code: 400 (bad parameter); Time: 2156ms; Content length: 27 bytes

첫번째 줄은 우리가 요청한 주소입니다.

POST http://localhost:8080/sample/valid

첫번째 공백 이후 다음 공백까지는 HTTP 응답 헤더입니다.

HTTP/1.1 400 bad parameter
Host: localhost:8080
Date: Tue, 19 Jan 2021 12:38:26 GMT
Connection: close
X-Powered-By: PHP/7.4.8
Cache-control: no-store, max-age=0, no-cache
Content-Type: application/json; charset=UTF-8
Debugbar-Time: 1611059906
Debugbar-Link: http://localhost:8080/index.php/?debugbar_time=1611059906

그리고 HTTP 본문이 시작합니다. HTTP 응답 메세지를 그대로 보여주는 것입니다.
응답 코드가 우리가 설정한 대로 400 bad parameter임을 확인할 수 있습니다. 추가로 HTTP 응답 바디에 JSON 형식으로 오류 메세지가 출력되었습니다. 우리가 원하는 대로 유효성 검증이 성공했다는 뜻입니다.

{
  "name": "이름이 필요합니다"
}

Response code: 400 (bad parameter); Time: 2156ms; Content length: 27 bytes

이번에는 모든 유효성을 검사해 보겠습니다. 기존의 valid.http 파일 하단에 아래 내용을 붙여 넣습니다.

###
# name, age required
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded


###
# name 최소 길이 검증
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=hi&age=50

###
# name 최대 길이 검증
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=abcdefghijklmn&age=50

###
# age 입력 안되었을 경우
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=hihi


###
# age 자연수인지 검증
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=abcde&age=-1

###
# age 자연수인지 검증
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=abcde&age=-5.5

###
# age 150 이상인지 검증
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=abcde&age=-160

###
# 모두 통과
POST http://localhost:8080/sample/valid
Content-Type: application/x-www-form-urlencoded

name=abcde&age=50

### 기호는 각 요청(request)을 구분합니다. 우리가 만든 valid.http 파일에는 총 9개의 요청이 있습니다. 하나씩 실행시키기는 번거로우므로 Run all requests in file을 클릭하고 run with no enviorment를 클릭합니다.
잠시 기다리면 http 클라이언트가 개별 요청을 하는 것을 볼 수 있습니다.

결과를 목록으로 확인할 수 있습니다. 목록을 클릭하면 각 요청과 응답을 확인할 수 있습니다.

profile
중년 아저씨. 10 + n년차 백엔드 개발자. 스타트업과 창업, 솔로프리너와 1인 기업에 관심 많아요.

0개의 댓글