3

I have a Laravel 4.2 application with the following route:

Route::group(['prefix' => 'api/v1'], function()
{
    Route::resource('service_logs', 'ServiceLogsController', [
        'only' => ['index', 'store', 'show']
    ]);
});

The ServiceLogsController controller extends from ApiController, which looks something like this cut down version:

class ApiController extends \BaseController {

    protected $statusCode = 200;

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

    public function setStatusCode($statusCode)
    {
        $this->statusCode = $statusCode;

        return $this;
    }

    public function respondInternalError($message = 'Internal Error!')
    {
        return $this->setStatusCode(500)->respondWithError($message);
    }

    public function respondWithError($message)
    {
        return Response::json([
            'error' => [
                'message' => $message,
                'status_code' => $this->getStatusCode()
            ]
        ], $this->getStatusCode());
    }

    // ...

}

What I'd like to do is, when ever an un-caught exception occurs, I want to call the respondInternalError() method on my ApiController, so that the API consumer has a consistent response rather than nothing or html whoops error.

To achieve this, I tried adding the following code in my app/start/global.php

App::error(function(Exception $exception, $code)
{
    Log::error($exception);

    if (Request::is('api/*'))
    {
        App::make('ApiController')->respondInternalError('Uncaught api exception error occurred - ' . $exception->getMessage());
    }
});

and to test it, I tried to make a POST request to the following url: /api/v1/service_logs/123.

this will not work, because that URL is a GET url, so Laravel throws the correct method not allowed exception. However, it's not getting caught.

Any idea how to implement a catch all exception handler per controller class basis?


Update Slightly improved working "global" api exception handler

App::error(function(Exception $exception, $code)
{
    Log::error($exception);

    if (Request::is('api/*'))
    {
        $errorName = Symfony\Component\HttpFoundation\Response::$statusTexts[$code];

        return App::make('ApiController')
            ->setStatusCode($code)
            ->respondWithError($errorName . ' error has occurred.');
    }
});

When an error occurs, you get this now (testing done in Chrome + Postman):

enter image description here

Latheesan
  • 23,247
  • 32
  • 107
  • 201
  • The call of Request::is() in a static manner returns an exception in my setting... – ITroubs Dec 19 '14 at 15:08
  • I tried calling `App::make('ApiController')->respondInternalError()` directly without checking request to see if my method was at-least getting called, it wasn't. – Latheesan Dec 19 '14 at 17:23
  • For those in Laravel 5 this may help you make this work. http://stackoverflow.com/questions/26630985/how-do-i-catch-exceptions-missing-pages-in-laravel-5/26630986#26630986 – DutGRIFF Jun 10 '15 at 22:41

1 Answers1

1

The solution is actually very very simple. You only need to return the return value of your controller function

if (Request::is('api/*'))
{
    return App::make('ApiController')->respondInternalError('Uncaught api exception error occurred - ' . $exception->getMessage());
}
lukasgeiter
  • 147,337
  • 26
  • 332
  • 270