1
votes

Environment: Laravel 5.1, PHP 5.6.10

I tried to implement App\Exceptions\Handler::render() to response error message in JSON format.

The app/Exceptions/Handler.php as follows:

// ignore..

public function render($request, Exception $e)
{
    if ($e instanceof ModelNotFoundException) {
        $e = new NotFoundHttpException($e->getMessage(), $e);
    } elseif ($e instanceof AbstractException) {
        return response()->apiJsonError(
                $e->getMessage(),
                $e->getErrors(),
                $e->statusCode());
    }

    // ignore...
}

In controller, it also throws an exception:

if (ArrayUtil::isIndexExceed($list, $maxIndex)) {
    // Index exceeds
    throw new App\Exceptions\ExceedingIndexException;
}

However, when the error occurs, the Handler::render() is not invoked. The response is the ExceedingIndexException stack.

The following part is Exception class

My custom exception class, ExceedingIndexException:

namespace App\Exceptions;

use App\Http\Responses\Error;
use App\Exceptions\AbstractException;

class ExceedingIndexException extends AbstractException
{
    public function __construct()
    {
        $message = 'Unable to execute';
        $error = new Error('exceeding_index_value');
        $statusCode = 400;

        parent::__construct($statusCode, $error, $message);
    }
}

The ExceedingIndexException class inherits AbstractException:

namespace App\Exceptions;

abstract class AbstractException extends \Exception
{
    protected $statusCode;
    protected $errors;

    public function __construct(
        $statusCode, $errors, $message, $code = 0, \Exception $previous = null) {
        parent::__construct($message, $code, $previous);

        $this->statusCode = $statusCode;
        $this->errors = $errors;
    }

    public function getStatusCode() 
    {
        return $this->statusCode;
    }

    public function getErrors() 
    {
        return $this->errors;
    }
}

Solution

I found my project depends on Dingo API for RESTful API. Because, Dingo also supports and registers its own exception handler, App\Exceptions\Handler doesn't be invoked.

I tried to use Custom Exception Responses in Dingo API as my Exception Handler to response error in JSON format. And it works for me.

2
I think the issue has nothing to do with your ExceedingIndexException which is located inside the controller. Apart from ModelNotFoundException what error should occur before AbstractException is triggered ? - Emeka Mbah

2 Answers

1
votes

Actually, you can replace the Dingo API error handler by a custom error handler. Get a copy of https://github.com/KIVagant/api/blob/develop/src/Exception/Handler.php and save it to YourApp\Exceptions\Api\V1\Handler.php. Add interface Dingo\Api\Contract\Debug\ExceptionHandler to it, then follow the instruction in Exceptions now can return any additional data.

use Dingo\Api\Contract\Debug\ExceptionHandler as DingoExceptionHandler;
class Handler implements ExceptionHandler, DingoExceptionHandler {

Replace the error handler, eg in boot ().

// Resolve YourApp\Exceptions\Api\V1\Handler ifself
$this->app->alias('api.exception', 'YourApp\Exceptions\Api\V1\Handler');

$this->app->singleton('api.exception', function ($app) {
    return new \YourApp\Exceptions\Api\V1\Handler($app['Illuminate\Contracts\Debug\ExceptionHandler'],
            $app['config']['api.errorFormat'], $app['config']['api.debug']);
});

Don't forget set error format. You can set up error format in boot(), eg:

// Set up error format
$this->app['api.exception']->setErrorFormat(...)
0
votes

Indeed, Dingo API took over the Exception handling.

You you face similar problems where Lumen Exception handler isn't handling anything, probably some package took over the handling. In this case it was Dingo API.

Register your custom response for the exception for Dingo API: https://github.com/dingo/api/wiki/Errors-And-Error-Responses#custom-exception-responses