I am building my API and I successfuly managed to catch some errors on a middleware I set up around my routes like following :
Route::group(['middleware' => \App\Http\Middleware\ExceptionHandlerMiddleware::class], function() {
Route::resource('/address', 'AddressController');
Route::resource('/country', 'CountryController');
Route::resource('/phone', 'PhoneController');
Route::resource('/user', 'UserController');
});
The middleware manage to catch the following exceptions :
Illuminate\Database\Eloquent\ModelNotFoundException
Illuminate\Validation\ValidationException
Exception
Which is great. I am also aware of a throttle mecanism that control the number of attempt in a route. So with postman I attacked my route http://localhost:8000/api/user
until I get the too many attemp
error.
The exception is throwed in the file located at :
/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php
And I also managed to get the type of exception it throws thanks to this forum topic : Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException
.
So in the end my middleware looks like this :
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Exception;
class ExceptionHandlerMiddleware
{
public function handle($request, Closure $next)
{
$output = $next($request);
try {
if( ! is_null( $output->exception ) ) {
throw new $output->exception;
}
return $output;
}
catch( TooManyRequestsHttpException $e ) {
return response()->json('this string is never showed up', 429);
}
catch( ValidationException $e ) {
return response()->json('validation error' 400);
}
catch( ModelNotFoundException $e ) {
return response()->json('not found', 404);
}
catch( \Exception $e ) {
return response()->json('unknow', 500);
}
}
}
You see the line this string is never showed up
? In fact it is never showed up, the original throttle exception from Illuminate always take the front.
QUESTION
How can I properly override the base error in a way that I could possibly (if possible) catch any exception without having to modify the illuminate file (in case of updates...) ?
Runing laravel 5.4.
EDIT
I cannot afford manually updating app/Http/Exception
files because my app will be shipped as a Service Provider for my futures others project. Also, I do not prefer taking the risk to erase some previous configuration on these files, as other "basic" routes in routes.php
may have their own exception catching procedures.
Best way to achieve that is to use app\Exceptions\Handler.php
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception)) {
if (request()->expectsJson()) {
switch ($exception->getStatusCode()) {
case 404:
return response()->json(['message' => 'Invalid request or url.'], 404);
break;
case '500':
return response()->json(['message' => 'Server error. Please contact admin.'], 500);
break;
default:
return $this->renderHttpException($exception);
break;
}
}
} else if ($exception instanceof ModelNotFoundException) {
if (request()->expectsJson()) {
return response()->json(['message' =>$exception->getMessage()], 404);
}
} {
return parent::render($request, $exception);
}
return parent::render($request, $exception);
}
In this demo you can add more Exception like } else if ($exception instanceof ModelNotFoundException) {
and tackle them.