Api: Custom ExceptionHandler

Created on 19 May 2015  ยท  56Comments  ยท  Source: dingo/api

Is it possible to overwrite the exception handler? If I would like to add custom syntax for the errors responses. Would be awesome if we could handle the entire exception handler outside of this package and use the default one that comes with the package out of the box.

Dingo\Api\Routing\Router::__construct() must be an instance of Dingo\Api\Exception\Handler, instance of App\Exceptions\Handler given,

Most helpful comment

Finally! Sorry to post on closed issue, but I must share this solution somewhere, I lost so many hours on it..
First of all create your own exception handler:
app/Exceptions/ApiExceptionsHandler.php

<?php
namespace App\Exceptions;

use Exception;
use Dingo\Api\Exception\Handler as DingoHandler;

class ApiExceptionsHandler extends DingoHandler
{
    public function handle(Exception $exception)
    {
        return parent::handle($exception);
    }
}

Then create wrapper for Laravel Dingo service provider:
app/Providers/DingoServiceProvider.php

<?php
namespace App\Providers;

use Dingo\Api\Provider\LaravelServiceProvider;
use App\Exceptions\ApiExceptionsHandler as ExceptionHandler;

class DingoServiceProvider extends LaravelServiceProvider
{
    protected function registerExceptionHandler()
    {
        $this->app->singleton('api.exception', function ($app) {
            return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
        });
    }
}

Lastly replace original Dingo service provider to this wrapper:
/config/app.com

...
'providers' => [
...
    //Dingo\Api\Provider\LaravelServiceProvider::class, // <- Remove this
    App\Providers\DingoServiceProvider::class,
...
];

That's it. Hope it'll help someone.

All 56 comments

I'm not sure what you're trying to do, but maybe this helps.
In your boot() function, you can do something like:

$exception = app('api.exception');

$exception->register(function(\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
    return Response::make(
        ['error' => 'Resource not found'],
        404);
});

which will then give you, for that exception:

{"error":"Resource not found"}

I want to map all thrown exceptions in this packages to my Laravel exception handler class App\Exceptions\Handler instead of using the exception handler in this package. Since I want custom syntax for my API responses.

Sorry, don't know how to do that.

@camilstaps Okay, thanks anyway.

Catch all the exceptions then. Same method as above except use the general
Exception class to capture them all.

On Tue, 19 May 2015 23:54 Vincent Klaiber [email protected] wrote:

@camilstaps https://github.com/camilstaps Okay, thanks anyway.

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-103504627.

@jasonlewis Do you have any example? I need to deregister Dingo\Api\Exception\Handler.

Well... you could rebind the Dingo exception handler as well. But what I was suggesting is to type-hint the standard Exception class in the Dingo exception handler and then pass the exception on to your applications handler.

app('api.exception')->register(function (Exception $exception) {
    return app('App\Exceptions\Handler')->render($excepton);
});

I tried to rebind the Dingo exception handler first but since it is type-hinted within the Router class I didn't get it to work. I'll try the snippet you've provided. Thanks!

You'd need to extend to rebind it. The type hint in the router should still
work through inheritance.

On Wed, 27 May 2015 16:03 Vincent Klaiber [email protected] wrote:

I tried to rebind the Dingo exception handler first but since it is
typehinted within the Router class I didn't get it to work. I'll try the
snippet you've provided. Thanks!

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-105767837.

Aah okay, didn't think about extending the handler form this package. I'll try it out. Thanks!

I might do up an interface for this though as that'll be easier in the long
run for folks that do what finer control over how exceptions are handled.
For some this might be a better option then using a catch all handler like
I demonstrated above where you type hint that default Exception class.

Would that better suit your needs? You'd then need to implement the handle
method on your class and in there you could do any customizing. Note that
you wouldn't have any of the default generic error responses that the
default handler implements.

On Wed, 27 May 2015 16:12 Vincent Klaiber [email protected] wrote:

Aah okay, didn't think about extending the handler form this package. I'll
try it out. Thanks!

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-105769421.

Yeah, thats sound like a great idea! I think it would make this package even more extendable for the users that want to have their custom setup. Though, the current setup is great out of the box.

I'm currently using https://github.com/GrahamCampbell/Laravel-Exceptions package which just recently got support for custom displayers. I've created custom JsonDisplayer for all HTTP responses and for all API validation errors that are thrown. The main reason behind it is because I've chosen to follow the JSON-API standards.

Maybe the easiest way to handle this is to add a option in the configuration files to just turn of the exception handler included in this package? Then users could do whatever they want with all errors thrown. What do you think?

Hm... If I do go that route I probably won't add it to the configuration
file to keep it from becoming bloated with things that most people won't
touch. How about a method on the handler that let's you disable it so all
exceptions are simply thrown back out to be handled by the user?

On Wed, 27 May 2015 16:20 Vincent Klaiber [email protected] wrote:

Yeah, thats sound like a great idea! I think it would make this package
even more extendable for the users that want to have their custom setup.
Though, the current setup is great out of the box.

I'm currently using https://github.com/GrahamCampbell/Laravel-Exceptions
package which just recently got support for custom displayers. I've created
custom JsonDisplayer for all HTTP responses and for all API validation
errors that are thrown. The main reason behind it is because I've chosen to
follow the JSON-API standards.

Maybe the easiest way to handle this is to add a option in the
configuration files to just turn of the exception handler included in this
package? Then users could do whatever they want with all errors thrown.
What do you think?

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-105772268.

Thats sound good. Maybe you could add it to the configuration but don't add it by default? Calling the config() but return true if the config doesn't exist? Do you've how would it look code-wise with the method?

The way I'm thinking...

app('api.exception')->disable()

On Wed, 27 May 2015 16:48 Vincent Klaiber [email protected] wrote:

Thats sound good. Maybe you could add it to the configuration but don't
add it by default? Calling the config() but return true if the config
doesn't exist? Do you've how would it look code-wise with the method?

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-105779204.

Thats sounds awesome! Let me know if I can help with that. Do you think it will be hard to implement?

Shouldn't take me more then a few minutes once I'm back at my computer.

On Wed, 27 May 2015 16:55 Vincent Klaiber [email protected] wrote:

Thats sounds awesome! Let me know if I can help with that. Do you think it
will be hard to implement?

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-105780916.

Sounds great! This is the only thing holding me back from merging the dingo branch into master in my current API project. Let me know how it goes.

To be honest the current exception handler could work if there only were a way to extend it even more. I'll try to extend it again.

I did manage to solve this rebinding the current exception handler. Though, I think the interface idea is still is great! Thanks for taking time to helping me out. Really appreciated :)

Yeah for sure mate. Going to implement an interface for this I think.

Cool, let me know how it goes!

There's now a contract for replacing it at Dingo\Api\Contract\Exception\Handler. The handle method is the only requirement.

Of course, you can still simply extend the handler and go from there. No need to rewrite it all if you don't need that level of control.

Awesome! I'll try it out.

Hey guys! sorry to bring back to life an already closed issue but I'm not sure if my doubts merit a brand new issue on the same subject.

I've been playing with dingo/api for the past couple of weeks and I'm pretty much pleased with it....except for 1 inconvinient situation I'm having with the whole exceptions handling management this package offers. At first I thought dingo would only automatically handle exceptions extending from Symfony\Component\HttpKernelException\HttpException as it's stated in the wiki...however when I throw a Illuminate\Database\Eloquent\ModelNotFoundException from a findOrFail() method... dingo seems to catch that too and render a 500 status code with the message "No query results for model...etc"

I've tried to make my own response to that exception but have had very little success since dingo's handler seems to act before anything I've tried so far... I found this issue to be my very own situation but it's not entirely clear to me how I'm supposed to extend the handler or implement the right method or even correctly register/bind it (tried doing the previous things in as many ways as I could think of). Could any of you guys give me some example on how to do this step by step? I'm not entirely new to laravel but I'm no master either :) so please bear with me. Thanks in advance!!

You can use the register method on the handler to setup your own responses
for certain exceptions. Just pass a closure with a type hinted exception.

On Fri, 17 Jul 2015 08:12 Oscar Espitia [email protected] wrote:

Hey guys! sorry to bring back to life an already closed issue but I'm not
sure if my doubs merit a brand new issue on the same subject.

I've been playing with dingo/api for the past couple of weeks and I'm
pretty much pleased with it....except for 1 inconvinient situation I'm
having with the whole exceptions handling management this package offers.
At first I thought dingo would only automatically handle exceptions
extending from Symfony\Component\HttpKernelException\HttpException as it's
stated in the wiki...however when I throw a
Illuminate\Database\Eloquent\ModelNotFoundException from a findOrFail()
method... dingo seems to catch that too and render a 500 status code with
the message "No query results for model...etc"

I've tried to make my own response to that exception but have had very
little success since dingo's handler seems to act before anything I've
tried so far... I found this issue to be my very own situation but it's not
entirely clear to me how I'm supposed to extend the handler or implement
the right method or even correctly register/bind it (tried doing the
previous things in as many ways as I could think of). Could any of you guys
give me some example on how to do this step by step? I'm not entirely new
to laravel but I'm no master either :) so please bear with me. Thanks in
advance!!

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122119182.

https://github.com/dingo/api/wiki/Errors-And-Error-Responses#custom-exception-responses

On Fri, 17 Jul 2015 08:17 Jason Lewis jason.[email protected] wrote:

You can use the register method on the handler to setup your own responses
for certain exceptions. Just pass a closure with a type hinted exception.

On Fri, 17 Jul 2015 08:12 Oscar Espitia [email protected] wrote:

Hey guys! sorry to bring back to life an already closed issue but I'm not
sure if my doubs merit a brand new issue on the same subject.

I've been playing with dingo/api for the past couple of weeks and I'm
pretty much pleased with it....except for 1 inconvinient situation I'm
having with the whole exceptions handling management this package offers.
At first I thought dingo would only automatically handle exceptions
extending from Symfony\Component\HttpKernelException\HttpException as it's
stated in the wiki...however when I throw a
Illuminate\Database\Eloquent\ModelNotFoundException from a findOrFail()
method... dingo seems to catch that too and render a 500 status code with
the message "No query results for model...etc"

I've tried to make my own response to that exception but have had very
little success since dingo's handler seems to act before anything I've
tried so far... I found this issue to be my very own situation but it's not
entirely clear to me how I'm supposed to extend the handler or implement
the right method or even correctly register/bind it (tried doing the
previous things in as many ways as I could think of). Could any of you guys
give me some example on how to do this step by step? I'm not entirely new
to laravel but I'm no master either :) so please bear with me. Thanks in
advance!!

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122119182.

Hey @jasonlewis ! thanks for the quick reply. Are you saying I can pass in "Illuminate\Database\Eloquent\ModelNotFoundException" to that method and instead of returning a response instance throw a different exception? if so where could I place that bit of code you've referenced? a service provider? I'm sorry but it's in the details where I'm struggling the most :(

You return a response instance from that method.

On Fri, 17 Jul 2015 08:24 Oscar Espitia [email protected] wrote:

Hey @jasonlewis https://github.com/jasonlewis ! thanks for the quick
reply. Are you saying I can pass in
"Illuminate\Database\Eloquent\ModelNotFoundException" to that method and
instead of returning a response instance throw a different exception? if so
where could I place that bit of code you've referenced? a service provider?
I'm sorry but it's in the details where I'm struggling the most :(

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122121046.

I'm not sure why you'd want to throw another exception. You're trying to
return a valid error response so that the client can still consume the
response and see why the error was returned.

As for where it goes. A service provider is a good a spot as any. :)

On Fri, 17 Jul 2015 08:28 Jason Lewis jason.[email protected] wrote:

You return a response instance from that method.

On Fri, 17 Jul 2015 08:24 Oscar Espitia [email protected] wrote:

Hey @jasonlewis https://github.com/jasonlewis ! thanks for the quick
reply. Are you saying I can pass in
"Illuminate\Database\Eloquent\ModelNotFoundException" to that method and
instead of returning a response instance throw a different exception? if so
where could I place that bit of code you've referenced? a service provider?
I'm sorry but it's in the details where I'm struggling the most :(

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122121046.

I see, well main reason I wanted to "catch" that particular exception and replace it with another is I'm using a small structure to format status codes and error codes in a centralized way and all the exceptions extending from that point will throw a simple HttpException that dingo catches to ultimately render the specific error. Is there any way I can achieve such behavour? or am I just going nuts with this?

BTW srsly thanks for your quick reply :)

The only way I can see you having that level of control is to either extend
or write your own handler and rebind the current one. You can rebind it by
replacing 'api.exception' with your instance. See more about that in this
issue above.

If I were you I'd probably simply extend it and override the
genericResponse method. You could probably do your logic there for
formatting your exceptions if you want.

On Fri, 17 Jul 2015 08:32 Oscar Espitia [email protected] wrote:

I see, well main reason I wanted to "catch" that particular exception and
replace it with another is I'm using a small structure to format status
codes and error codes in a centralized way and all the exceptions extending
from that point will throw a simple HttpException that dingo catches to
ultimately render the specific error. Is there any way I can achieve such
behavour? or am I just going nuts with this?

BTW srsly thanks for your quick reply :)

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122122456.

Hello @jasonlewis me again... sadly :( I've been trying to do what you suggested I created my own Handler class called ApiHandler extending from Dingo\Api\Exception\Handler and overriding the genericResponse as follows:

// App\Exceptions\ApiHandler.php
protected function genericResponse(Exception $exception)
{
    if ($exception instanceof Illuminate\Database\Eloquent\ModelNotFoundException) {
        throw new App\Exceptions\Models\ModelNotFoundException();
    }
    parent::genericResponse($exception);
}

Then I added this line to the register method inside App\Providers\AppServiceProvider:

$this->app->bind('api.exception', 'App\Exceptions\ApiHandler');

I'm uncertain as for what am I doing wrong but it seems like I've completely broken the api responses as I get this message while testing any endpoint in Postman: Could not get any response.

I've tried making my ApiHandler not only extend Dingo\Api\Exception\Handler but also implement the Dingo\Api\Contract\Exception\Handler (ofc adding the corresponding handle method), even binding my ApiHandler to that contract in a similar fashion using the register method of App\Providers\AppServiceProvider, for crying outloud I've even tried creating a singleton within bootstrap/app.php and still have had zero success.

I'm sorry to bother you once again but could you please point me in the right direction here? how can I perform this rebind process you described and am I placing it in the wrong provider/method? An example would go a long way! Thanks!

BTW I should also mention that in some cases I've managed to make the responses work in Postman...however still have no success with that ModelNotFoundException I keep getting this instead of my formatted response:

{
  "message": "No query results for model [App\\\\Models\\\\Company].",
  "status_code": 500
}

I'm going to be overhauling exception handling today because I'm not happy with it, aside from the fact it doesn't behave properly in Lumen.

But I have to ask, what is the benefit you're getting by rethrowing the exceptions as a generic HttpException? It seems like you could simply catch all exceptions and format the response as you see fit. You can't throw an exception from within the handle method of the exception handler. Well, you can, but I have no idea what the result would be. It MUST return a response instance.

Well it all started with the incremental APIs series and the interesting idea of keeping responses agnostic without writing status/error codes directly into each response simply because it might become a nightmare to change in the future (this is true for long-term-support big projects). So I began wrapping my head around the idea of creating contracts to centralize those using constants so I can easily just implement such contracts wherever I need to send a response. I started creating different exceptions for different particular situation such as TokenNotFound or TokenExpired and formatting the status code as well as the message to be returned (array including specific error code) all of them extending from HttpException and it all worked like a charm. I completely got rid of the need to have error responses in my controllers, I'd simply throw a particular exception.

At first I thought that dingo/api had it well covered with its catching of any HttpException thrown anywhere in the framework but then I ran into the ModelNotFoundException situation (very common) so I thought the easiest and most efficient way to handle that was to catch any and every ModelNotFoundException thrown by the query builder so I could just throw a different exception instead, one that'd extend from HttpException (formatted in a same fashion as the Token exceptions I mentioned above) so ultimately wouldn't mean much hassle and would still use dingo/api error response system.

Perhaps I'm overcomplicating myself here and should instead do what you advice me to...catch all exceptions and use my approach instead but allowing for actual error responses to be sent instead of that last step where I rely on dingo to do it for me.

Just so I don't keep messing my head and going around the problem for so long...what is the best way to efficiently disable all error responses sent by dingo/api?

Also, I must say it seems like the exception handling has given your amazing package lots of drawbacks and unexpected situations because everyone needs a different approach at it...exception handling ultimately includes a lot of customization. May I suggest to perhaps take a step back and go with a much simpler approach? Maybe if it's too difficult to make it work as flexible as possible so it pleases everyone while still keeping it easy to use...you should not include it at all? I'm thinking modularizing certain parts of your package to be completely replaceable/optional so if someone is not happy with your default behavour for exception handling...they could just as easy implement something else (3rd party exception handling packages or their own)?

I'll write a note detailed response in the morning but I will say this...
The exception handling is tough because I either do nothing and leave it up
to devs to implement their own exception handling, or I try to implement
something like I have now. There isn't really any middle ground.

I'll probably try and revise it a bit though. If I can. Like you said,
everyone wants exceptions differently. So perhaps not worrying about a
handler is the best approach. We'll see.

On Sun, 19 Jul 2015 00:32 Oscar Espitia [email protected] wrote:

Well it all started with the incremental APIs series and the interesting
idea of keeping responses agnostic without writing status/error codes
directly into each response simply because it might become a nightmare to
change in the future (this is true for long-term-support projects). So I
began wrapping my head around the idea of creating contracts to centralize
those using constants so I can easily just implement such contracts
wherever I need to send a response. I started creating different exceptions
for different particular situation such as TokenNotFound or TokenExpired
and formatting the status code as well as the message to be returned (array
including specific error code) all of them extending from HttpException and
it all worked like a charm. I completely got rid of the need to have error
responses in my controllers, I'd simply throw a particular exception.

At first I thought that dingo/api had it well covered with its catching of
any HttpException thrown anywhere in the framework but then I ran into the
ModelNotFoundException situation (very common) so I thought the easiest and
most efficient way to handle that was to catch any and every
ModelNotFoundException thrown by the query builder so I could just throw a
different exception instead, one that'd extend from HttpException
(formatted in a same fashion as the Token exceptions I mentioned above) so
ultimately wouldn't mean much hassle and would still use dingo/api error
response system.

Perhaps I'm overcomplicating myself here and should instead do what you
advice me to...catch all exceptions and use my approach instead but
allowing for actual error responses to be sent instead of that last step
where I rely on dingo to do it for me.

Just so I don't keep messing my head and going around the problem for so
long..._what is the best way to efficiently disable all error responses
sent by dingo/api?_

Also, I must say it seems like the exception handling has given your
amazing package lots of drawbacks and unexpected situations because
everyone needs a different approach at it...exception handling ultimately
includes a lot of custiomization. May I suggest to perhaps take a step back
and go with a much simpler approach? Maybe if it's too difficult to make it
work as flexible as possible so it pleases everyone while still keeping it
easy to use...you should not include it at all? I'm thinking modularizing
certain parts of your package to be completely replaceable/optional so if
someone is not happy with your default behavour for exception
handling...they could just as easy implement something else (3rd party
exception handling packages or their own)?

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122549756.

Also worth noting is that you can't throw an exception from within Laravels
handler. You'll find that you probably need to catch the model not found
exception earlier and rethrow it, regardless of what changes I make. Is
that a possibility?

Or override the eloquent method that throws the exception.

On Sun, 19 Jul 2015 00:38 Jason Lewis jason.[email protected] wrote:

I'll write a note detailed response in the morning but I will say this...
The exception handling is tough because I either do nothing and leave it up
to devs to implement their own exception handling, or I try to implement
something like I have now. There isn't really any middle ground.

I'll probably try and revise it a bit though. If I can. Like you said,
everyone wants exceptions differently. So perhaps not worrying about a
handler is the best approach. We'll see.

On Sun, 19 Jul 2015 00:32 Oscar Espitia [email protected] wrote:

Well it all started with the incremental APIs series and the interesting
idea of keeping responses agnostic without writing status/error codes
directly into each response simply because it might become a nightmare to
change in the future (this is true for long-term-support projects). So I
began wrapping my head around the idea of creating contracts to centralize
those using constants so I can easily just implement such contracts
wherever I need to send a response. I started creating different exceptions
for different particular situation such as TokenNotFound or TokenExpired
and formatting the status code as well as the message to be returned (array
including specific error code) all of them extending from HttpException and
it all worked like a charm. I completely got rid of the need to have error
responses in my controllers, I'd simply throw a particular exception.

At first I thought that dingo/api had it well covered with its catching
of any HttpException thrown anywhere in the framework but then I ran into
the ModelNotFoundException situation (very common) so I thought the easiest
and most efficient way to handle that was to catch any and every
ModelNotFoundException thrown by the query builder so I could just throw a
different exception instead, one that'd extend from HttpException
(formatted in a same fashion as the Token exceptions I mentioned above) so
ultimately wouldn't mean much hassle and would still use dingo/api error
response system.

Perhaps I'm overcomplicating myself here and should instead do what you
advice me to...catch all exceptions and use my approach instead but
allowing for actual error responses to be sent instead of that last step
where I rely on dingo to do it for me.

Just so I don't keep messing my head and going around the problem for so
long..._what is the best way to efficiently disable all error responses
sent by dingo/api?_

Also, I must say it seems like the exception handling has given your
amazing package lots of drawbacks and unexpected situations because
everyone needs a different approach at it...exception handling ultimately
includes a lot of custiomization. May I suggest to perhaps take a step back
and go with a much simpler approach? Maybe if it's too difficult to make it
work as flexible as possible so it pleases everyone while still keeping it
easy to use...you should not include it at all? I'm thinking modularizing
certain parts of your package to be completely replaceable/optional so if
someone is not happy with your default behavour for exception
handling...they could just as easy implement something else (3rd party
exception handling packages or their own)?

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-122549756.

Okay after a bit of deliberating I don't think I'm going to change it. For 95% of people it will work well. For the remaining 5% you already have the option of simply replacing it with your own handler. All you need to do is rebind the api.exception instance and update the Illuminate\Contracts\Debug\ExceptionHandler binding as well.

You should implement the Dingo\Api\Contract\Debug\ExceptionHandler interface as well so that you can handle any exceptions. That way you have complete control over the exceptions.

:+1:

@jasonlewis I am quite new to Laravel and I am trying to rebind api.exception and implement totally custom exception handler. I can't get it work.

I have custom exception handler like this:

class Handler extends \Dingo\Api\Exception\Handler {
    function handle(Exception $exception) {
        dd("test");
        return parent::handle($exception);
    }
}

I have registered the handler in AppServiceProvider's register() method:

$this->app->bind('api.exception', 'App\Exceptions\Handler');

The handle() method never get's called. What am I doing wrong?

Thanks!

@jasonlewis What's the best way of implementing Bugsnag error reporting into the exception handler? Completely baffled by it. Thanks.

Would that automatically pickup exceptions when using Dingo? That's what
i'm having issues with - with the Bugsnag laravel package you need to
replace the exception handler which you can't easily do with Dingo.

On 2 February 2016 at 11:58, Vincent Klaiber [email protected]
wrote:

@LeeMcNeil https://github.com/LeeMcNeil I would use
https://github.com/altthree/bugsnag by @GrahamCampbell
https://github.com/GrahamCampbell

โ€”
Reply to this email directly or view it on GitHub
https://github.com/dingo/api/issues/411#issuecomment-178529865.

Regards

Lee McNeil

Email: [email protected]
Skype: lee.j.mcneil

Tebex Limited Registered in England & Wales No. 08129184.

Finally! Sorry to post on closed issue, but I must share this solution somewhere, I lost so many hours on it..
First of all create your own exception handler:
app/Exceptions/ApiExceptionsHandler.php

<?php
namespace App\Exceptions;

use Exception;
use Dingo\Api\Exception\Handler as DingoHandler;

class ApiExceptionsHandler extends DingoHandler
{
    public function handle(Exception $exception)
    {
        return parent::handle($exception);
    }
}

Then create wrapper for Laravel Dingo service provider:
app/Providers/DingoServiceProvider.php

<?php
namespace App\Providers;

use Dingo\Api\Provider\LaravelServiceProvider;
use App\Exceptions\ApiExceptionsHandler as ExceptionHandler;

class DingoServiceProvider extends LaravelServiceProvider
{
    protected function registerExceptionHandler()
    {
        $this->app->singleton('api.exception', function ($app) {
            return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
        });
    }
}

Lastly replace original Dingo service provider to this wrapper:
/config/app.com

...
'providers' => [
...
    //Dingo\Api\Provider\LaravelServiceProvider::class, // <- Remove this
    App\Providers\DingoServiceProvider::class,
...
];

That's it. Hope it'll help someone.

@shanginn thanks a lot, it work great.

@shanginn thanks a lot, it work great. :tada:

@shanginn after doing this, I'm getting 500 response and no response data :-(

@shanginn I've followed exactly like that but it didn't work. I'm getting 500 response and no response data.

Hi guys

It's actually very easy to override the dingo exception handler. Just make a new exception handler class in your app, which extends the dingo one, and do the following in your AppServiceProvider

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerExceptionHandler();
    }

    /**
     * Register the exception handler - extends the Dingo one
     *
     * @return void
     */
    protected function registerExceptionHandler()
    {
        $this->app->singleton('api.exception', function ($app) {
            return new ApiExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], Config('api.errorFormat'), Config('api.debug'));
        });
    }

In this case, the ApiExceptionHandler is my custom exception handler. And so in extending dingo's one, you are free to override any methods you wish.

And the class you want to extend is Dingo\ApiException\Handler

@rohitkhatri @adhatama . Hi guys, I had this problem before, but I tried to solve it, it work great.

app/Providers/DingoServiceProvider.php Change to

<?php
namespace App\Providers;

use Dingo\Api\Provider\DingoServiceProvider as DingoServiceProviders;
use App\Exceptions\ApiExceptionsHandler as ExceptionHandler;

class DingoServiceProvider extends DingoServiceProviders
{
    protected function registerExceptionHandler()
    {
        $this->app->singleton('api.exception', function ($app) {
            return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
        });
    }
}

Finally! Sorry to post on closed issue, but I must share this solution somewhere, I lost so many hours on it..
First of all create your own exception handler:
app/Exceptions/ApiExceptionsHandler.php

<?php
namespace App\Exceptions;

use Exception;
use Dingo\Api\Exception\Handler as DingoHandler;

class ApiExceptionsHandler extends DingoHandler
{
    public function handle(Exception $exception)
    {
        return parent::handle($exception);
    }
}

Then create wrapper for Laravel Dingo service provider:
app/Providers/DingoServiceProvider.php

<?php
namespace App\Providers;

use Dingo\Api\Provider\LaravelServiceProvider;
use App\Exceptions\ApiExceptionsHandler as ExceptionHandler;

class DingoServiceProvider extends LaravelServiceProvider
{
    protected function registerExceptionHandler()
    {
        $this->app->singleton('api.exception', function ($app) {
            return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
        });
    }
}

Lastly replace original Dingo service provider to this wrapper:
/config/app.com

...
'providers' => [
...
    //Dingo\Api\Provider\LaravelServiceProvider::class, // <- Remove this
    App\Providers\DingoServiceProvider::class,
...
];

That's it. Hope it'll help someone.

In your ApiExceptionsHandler, are you able to access the request object? I need to parse the route.

@double-reinbows You actually don't need to override the service provider at all - that is way too much effort, have a look at my post just up above.

@specialtactics thank you for your advice but none of the suggestions here provide a way for me to access the original request which I kinda need to redirect non-GET requests (trying to implement versioning).

@double-reinbows you can get request data globally using the request() laravel global helper.

App\Providers\DingoServiceProvider::class

In case you are looking for a more robust error handler where jwt is included.
I have modified the ApiExceptionsHandler as shown in the code below.

`<?php

namespace App\Exceptions;

use Exception;
use Dingo\Api\Exception\Handler as DingoHandler;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;

class ApiExceptionsHandler extends DingoHandler
{
    /**
     * @param \Dingo\Api\Http\Request $request
     * @param Exception $exception
     * @return \Illuminate\Http\JsonResponse|mixed
     * @throws Exception
     */
    public function render($request, Exception $exception)
    {
        // This will replace our 404 response with a JSON response.
        if ($exception instanceof ModelNotFoundException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'Resource item not found.'
            ], 404);
        }

        if ($exception instanceof NotFoundHttpException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'Resource not found.'
            ], 404);
        }

        if ($exception instanceof MethodNotAllowedHttpException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'Method not allowed.'
            ], 405);
        }

        if($exception instanceof TokenInvalidException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'Token is invalid'
            ], 403);
        }

        if ($exception instanceof TokenExpiredException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'Token is expired'
            ], 403);
        }

        if ($exception instanceof JWTException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => 'something is wrong'
            ], 403);
        }

        if($exception instanceof UnauthorizedHttpException || $request->wantsJson()) {
            return response()->json([
                'status' => false,
                'error' => $exception->getMessage()
            ], $exception->getStatusCode());
        }

        return parent::render($request, $exception);
    }
}`

I hope someone finds this helpful. Cheers!!!

I have faced the same issue and here is my custom solution this is simple and work for me,
Hope you guys found working in your case also.

`<?php
namespace App\Exceptions;
use Dingo\Api\Http\Request;

use Dingo\Api\Exception\Handler as DingoHandler;
use App\Helpers\API\General; // This is my Custom Handler function which i used to format response 

use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
/**
 This class extends the Dingo API Exception Handler, and can be used to modify it's functionality, if required
 Unless you have a specific-use case and understand what you are doing, it's best not to modify this.

 Class ApiHandler
*/
class ApiExceptionHandler extends DingoHandler
{
public function handle($exception)
    {
        // Here i checked for API_DEBUG so i can send response accordingly with my Custom Exception Handler as well.
        $debug = env('API_DEBUG',false);

        if(!$debug){
            // Dingo has already handle this but we need a API structure with our response so we have added here
            $request = new Request();

            if ($exception instanceof MethodNotAllowedHttpException){
                $response = General::setResponse('METHOD_NOT_ALLOWED'); // Here i used my helper function for format
                return send_json_response($request, $response); // This is also custom helper function which i used to finally send response
            }
        }
        return parent::handle($exception);
    }
}`
Was this page helpful?
0 / 5 - 0 ratings