Hi,
Say, you want any API related errors to be handled by Dingo's Exception Handler. But other than that, you want to handle it your own, with your own message.
The current setup will output the error verbosely. For example, when the application faced an ErrorException, it will return this response:
{
"error": {
"message": "Trying to get property of non-object",
"status_code": 500
}
}
What I want is something like:
{
"error": {
"message": "Ooops. We have faced some problem. Our team has been notified. Fixing it now.",
"status_code": 500
}
}
I could register a handler for the ErrorException. But what I really would like to do is handle any exception that is not an instanceof HttpException.
I also realised that HttpException is extending the RuntimeException exception. That means, I cannot have my own RuntimeException handler, because that will also catch the HttpException raised by the app.
Do you guys have any solution for how I should approach the above problem? Or do you guys think that I have viewed the above problem incorrectly.
Thanks in advance for your help.
I have a tried at solving the above problem. My solution so far is to override the Dingo Exception Handler:
<?php
namespace App\Exceptions;
use Dingo\Api\Exception\Handler;
use Exception;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ApiExceptionHandler extends Handler
{
public function handle(Exception $exception)
{
if ($exception instanceof HttpException) {
return $this->genericResponse($exception);
}
return $this->handleRegisteredExceptions($exception);
}
protected function handleRegisteredExceptions(Exception $exception)
{
foreach ($this->handlers as $hint => $handler) {
if (! $exception instanceof $hint) {
continue;
}
if ($response = $handler($exception)) {
if (! $response instanceof Response) {
$response = new Response($response, $this->getExceptionStatusCode($exception));
}
return $response;
}
}
return $this->genericResponse(new Exception("Something went wrong from our side. Our team has been notified about this error, so that they can fix the problem soon. We are sorry for the inconvenience."), 500);
}
}
So, any HttpException are handled by the original handler. Other than that, it is handled by the above Handler.
In order for the above Handler to work, I register it to override the api.exception binding. This is from my AppServiceProvider::register method
$this->app->singleton('api.exception', function($app) {
return new ApiExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], config('api.errorFormat'), config('api.debug'));
});
So far it's working fine.
But I would like to know the opinion from the community, do you think the above approach is good?
Nope, can be solved much easier...
app(Dingo\Api\Exception\Handler::class)->register(function (Exception $exception) {
if (! $exception instanceof Symfony\Component\HttpKernel\Exception\HttpException) {
throw new Symfony\Component\HttpKernel\Exception\HttpException(500, 'Woops, something went really wrong.');
}
});
Or just return a custom response instead of throwing an HttpException.
Basically, catch all exceptions, then only if the exception is not an instance of the HttpException will something be thrown/returned. Otherwise just do nothing, it'll be handled by the generic handler then.
If you want to customize ur ignored list, you can do the following:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Exception;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//fix key was too long error
Schema::defaultStringLength(191);
//list of exceptions we don't want to be reported by dingo exception handler
$dontReport = [
\Illuminate\Auth\AuthenticationException::class,
\Illuminate\Auth\Access\AuthorizationException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
\Illuminate\Database\QueryException::class
];
app('Dingo\Api\Exception\Handler')->register(function (Exception $exception) use ($dontReport) {
if (in_array(get_class($exception), $dontReport)) {
throw new HttpException(500, 'Woops, something went really wrong.');
}
});
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
Most helpful comment
Nope, can be solved much easier...
Or just return a custom response instead of throwing an
HttpException.Basically, catch all exceptions, then only if the exception is not an instance of the
HttpExceptionwill something be thrown/returned. Otherwise just do nothing, it'll be handled by the generic handler then.