본문으로 바로가기

[Laravel] Error 핸들링 (CustomException)

category Framework/Laravel 2021. 11. 19. 17:19
라라벨의 모든 예외(Exception)들은 별도의 catch 블록을 사용하지 않는 경우 App\Exceptions\Handler 클래스에 의해 로그를 남기고 사용자에게 응답을 보여주도록 되어있다.
또한 별도의 Exception Class 를 생성하여 report(), render() 메소드를 통해 핸들링을 할수 있도록 지원하고 있으며 해당 글에서는 별도의 예외클래스를 생성하여 에러를 핸들링하는 예제에 대해 소개하고자 한다.

Exception Class 생성하기

Exception Class 의 생성은 라라벨에서 제공하는 artisan 커맨드를 통해 생성하는 방법과 직접 파일을 추가하는 방법이 있다. artisan 커맨드를 이용할 경우 app\Exception 경로에 클래스가 생성되며, 반드시 해당 네임스페이스가 아니어도 상관없다.

root@fbb55136d2a1:/var/www/tailerbox# artisan make:exception ValidateException
Exception created successfully.

위와 같이 artisan 명령어를 사용하면  app\Exception 네임스페이스에 ValidateException 클래스가 생성이 되는 것을 확인할 수 있다. artisan 명령어를 사용하지 않고 직접 생성하는 경우 해당 네임스페이스를 사용하지 않아도 무방하지만 Exception Class 를 상속받아야 한다.

<?php

namespace App\Exceptions;

use Exception;

class ValidateException extends Exception
{
    //
}

상기와 같이 생성된 클래스에 로그 및 응답결과를 반환하기 위한 메소드를 추가 해보자.

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
use Symfony\Component\HttpFoundation\Response;

class ValidateException extends Exception
{
    /**
     * @var \Illuminate\Support\MessageBag $messageBag
     */
    public $messageBag;

    /**
     * @param Validator $validator
     */
    public function __construct(Validator $validator)
    {
        $this->messageBag = $validator->getMessageBag();
        parent::__construct($this->messageBag->first(), Response::HTTP_UNPROCESSABLE_ENTITY);
    }

    public function report()
    {
        Log::error(
            sprintf("%s::%s", __CLASS__, $this->messageBag->first()),
            $this->messageBag->messages()
        );
    }

    public function render()
    {
        return \response([
            'errors' => $this->messageBag->all()
        ], Response::HTTP_UNPROCESSABLE_ENTITY);
    }
}

예외가 발생하는 경우 해당 클래스에 선언된 report() 메소드가 실행되고, 응답을 반환하기 위한 render() 메소드가 순차적으로 실행된다.

해당 예외의 경우 예외가 발생할 때 Validator 의 인스턴스를 주입받아 유효성 검증에 실패한 인자의 필드 및 메시지를 로그에 남기고 render() 메소드를 통해 Response Body 및 Status 를 반환한다.

 

※ 주의할 점

아래와 같이 예외발생 구문에 try {...} catch (Throwable $e) {...} 이 존재하고 try block 내에서 예외를 던지는 경우 report/render 메소드가 아닌 catch 블록에 명시된 코드에 의해 예외가 핸들링 된다.

try {
    if ($validator->fails()) {
        throw new ValidateException($validator);
    }
} catch (Throwable $e) {
    if ($e instanceof ValidateException) {
        /* report/render 메소드가 실행되지 않음. */
    }
}