Igor Simic
2 years ago

How to catch Laravel exception and return json response - example


How to handle Laravel exception and send json response with correct status code? Well, to make this possible we can use Laravel middleware to intercept response, check is the response exception and check does this request expecting json type as return. So let' start.

First let's open our middleware Laravel exception handler, go to app/Exceptions/Handler.php and in render function we will enter our code.

so first let's check is this request expecting json as return:
public function render($request, Exception $exception)
{

    // is this request asks for json?
    if( $request->header('Content-Type') == 'application/json'){
    
    }

}
If this request is asking for json response lets check is this Exception?
public function render($request, Exception $exception)
{

    // is this request asks for json?
    if( $request->header('Content-Type') == 'application/json'){
       
       // do we have exception triggered for this response?
       if ( !empty($exception) ) {

       }

    }

}

next, let's set up default messages and messages if debug is enabled:
public function render($request, Exception $exception)
{

    // is this request asks for json?
    if( $request->header('Content-Type') == 'application/json'){
       
      // do we have exception triggered for this response?
      if ( !empty($exception) ) {

        // set default error message
        $response = [
            'error' => 'Sorry, can not execute your request.'
        ];

        // If debug mode is enabled
        if (config('app.debug')) {
            // Add the exception class name, message and stack trace to response
            $response['exception'] = get_class($exception); // Reflection might be better here
            $response['message'] = $exception->getMessage();
            $response['trace'] = $exception->getTrace();
        }
        
      }

    }

}


and now let's check what kind of exception this is and can we get the response from exception, and if not we will se our own and return json as a response:
public function render($request, Exception $exception)
{

    // does this request asks for json?
    if( $request->header('Content-Type') == 'application/json'){
       
      // do we have exception triggered for this response?
      if ( !empty($exception) ) {

        // set default error message
        $response = [
            'error' => 'Sorry, can not execute your request.'
        ];

        // If debug mode is enabled
        if (config('app.debug')) {
            // Add the exception class name, message and stack trace to response
            $response['exception'] = get_class($exception); // Reflection might be better here
            $response['message'] = $exception->getMessage();
            $response['trace'] = $exception->getTrace();
        }

        // default status
        $status = 400;

        // get correct status code

        // is this validation exception
        if($exception instanceof ValidationException){

            return $this->convertValidationExceptionToResponse($exception, $request);

            // is it authentication exception
        }else if($exception instanceof AuthenticationException){

            $status = 401;

            $response['error'] = 'Can not finish authentication!';

            //is it DB exception
        }else if($exception instanceof \PDOException){

            $status = 500;

            $response['error'] = 'Can not finish your query request!';

            // is it http exception (this can give us status code)
        }else if($this->isHttpException($exception)){

            $status = $exception->getStatusCode();

            $response['error'] = 'Request error!';

        }else{

            // for all others check do we have method getStatusCode and try to get it
            // otherwise, set the status to 400
            $status = method_exists($exception, 'getStatusCode') ? $exception->getStatusCode() : 400;

        }

        return response()->json($response,$status);

      }

    }

}

Ok so the full Handler.php class should look like this:
<?php

namespace App\Exceptions;

use Exception;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * @param Exception $exception
     * @return void
     * @throws Exception
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {

        // is this request asks for json?
        if( $request->header('Content-Type') == 'application/json'){

            /*  is this exception? */

            if ( !empty($exception) ) {

                // set default error message
                $response = [
                    'error' => 'Sorry, can not execute your request.'
                ];

                // If debug mode is enabled
                if (config('app.debug')) {
                    // Add the exception class name, message and stack trace to response
                    $response['exception'] = get_class($exception); // Reflection might be better here
                    $response['message'] = $exception->getMessage();
                    $response['trace'] = $exception->getTrace();
                }

                $status = 400;

                // get correct status code

                // is this validation exception
                if($exception instanceof ValidationException){

                    return $this->convertValidationExceptionToResponse($exception, $request);

                    // is it authentication exception
                }else if($exception instanceof AuthenticationException){

                    $status = 401;

                    $response['error'] = 'Can not finish authentication!';

                    //is it DB exception
                }else if($exception instanceof \PDOException){

                    $status = 500;

                    $response['error'] = 'Can not finish your query request!';

                    // is it http exception (this can give us status code)
                }else if($this->isHttpException($exception)){

                    $status = $exception->getStatusCode();

                    $response['error'] = 'Request error!';

                }else{

                    // for all others check do we have method getStatusCode and try to get it
                    // otherwise, set the status to 400
                    $status = method_exists($exception, 'getStatusCode') ? $exception->getStatusCode() : 400;

                }

                return response()->json($response,$status);

            }
        }

        return parent::render($request, $exception);
    }
}

THE END.