Default route / notFound Error Handling / HttpNotFoundException / Custom Exception Handling in Slim 4 PHP

1.9k views Asked by At

I want to create a Slim 4 compatible custom error page /JSON reply that is returned, when a non-existing route is request.

Default route (Slim 3)

I've recently upgraded from Slim 3 to Slim 4. With Slim 3, I had a default route that perfectly did the job:

   $app->any('/[{path:.*}]', function (Request $request, Response $response, array $args) {
      // catching any other requests...
      /* ... creating JSON error object and write it to $slimresponse ... */
      return ($slimresponse);
   });

However, when I do this in Slim 4, I get an error

Type: FastRoute\BadRouteException
Code: 0
Message: Cannot register two routes matching "/" for method "GET"

This obviouosly means that Slim recognizes this as double entry for GET /, which is disallowed in Slim 4.

This article also provided no help for Slim 4, unfortunately.

notFound

Furthermore, according to https://www.javaer101.com/en/article/13830039.html, I've tried to add

$app->notFound(function () use ($app) {
    $app->response->setStatus(403);
    echo "Forbidden";
    //output 'access denied', redirect to login page or whatever you want to do.
});

to my routes.php, but it doesn't work:

Call to undefined method Slim\App::notFound()

HttpNotFoundException

Finally, I've also tried to create an error handling method (specifically for HttpNotFoundException, although I don't know how to separate HttpNotImplementedException) https://www.slimframework.com/docs/v4/middleware/error-handling.html, without any success.

Any help is highly appreciated.

1

There are 1 answers

0
BogisW On BEST ANSWER

I'd posted the question after searching for two or more hours.

After submitting the question, I've found the answer here. https://odan.github.io/2020/05/27/slim4-error-handling.html#catching-404-not-found-errors

Here is my new middleware.php:

use Slim\App;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Exception\HttpNotFoundException;
use Slim\Middleware\ErrorMiddleware;
use Middlewares\TrailingSlash;
use Slim\Psr7\Response; 

return function (App $app) {
    // Parse json, form data and xml
    $app->addBodyParsingMiddleware();

    // Add the Slim built-in routing middleware
    $app->addRoutingMiddleware();

    // always add a trailing slash
    $app->add(new TrailingSlash(true));

    // Add BasePathMiddleware
    $app->add(BasePathMiddleware::class);

    // HttpNotFoundException
    $app->add(function (ServerRequestInterface $request, 
                        RequestHandlerInterface $handler) {
       try {
          return $handler->handle($request);
       } catch (HttpNotFoundException $httpException) {
           $response = (new Response())->withStatus(404);
           $response->getBody()->write('404 Not found');

           return $response;
       }
    });

    // Catch exceptions and errors
    $app->add(ErrorMiddleware::class);
};

For everyone looking for an extension with another exception class, extend the code above by:

       try {
          return $handler->handle($request);
       } catch (HttpNotFoundException $httpException) {
           $response = (new Response())->withStatus(404);
           $response->getBody()->write('404 Not found');

           return $response;
       } catch (HttpMethodNotAllowedException $httpException) {
           $response = (new Response())->withStatus(405);
           $response->getBody()->write('405 Method not allowed. Please use one of the following: '.implode(',',$httpException->getAllowedMethods()));

           return $response;
       }

Other exception classes can be found on https://github.com/slimphp/Slim/tree/4.x/Slim/Exception

This is how you can get and display the exception class for developing/debugging purposes:

      } catch (Exception $e) {
         $response = (new Response())->withStatus(500);
         $response->getBody()->write(get_class($e));

         return $response;
      }