How to catch "too many attempt" exception in a middleware Laravel 5

10,245

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.

Share:
10,245
Anwar
Author by

Anwar

Fullstack developper @ Carlili

Updated on June 09, 2022

Comments

  • Anwar
    Anwar almost 2 years

    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.

    • Kyslik
      Kyslik almost 7 years
      Exact version of Laravel is needed, since error handling has changed over the years.
    • Kyslik
      Kyslik almost 7 years
      You may want to re-read laravel.com/docs/5.4/errors#the-exception-handler that part and come back if that does not work for you.
    • Kyslik
      Kyslik almost 7 years
      I read updated question, take a step back what if multiple packages want to "handle too many requests" what will Laravel do? Well it will break, so you need to handle HTTP based exceptions at application level not at service provider level and do not try..catch in middleware its not good solution. Think about it out of the box for a while. "Global" handler is the only way, you may check for request data and determine that it was meant for "your package" and handle it and if not just re-throw it as is.
    • Misbah Ahmad
      Misbah Ahmad over 4 years
      For laravel 5.6, you just have to handle the laravel.com/api/5.8/Illuminate/Http/Exceptions/…