Restangular - How to override Error Interceptors

sam picture sam · Jan 18, 2015 · Viewed 8.7k times · Source

I am using AngularJS v1.2.16 with Restangular v1.4.0, and would like to know if it's possible to override the ErrorInterceptor. If yes, how? if no, how can I work it around?

I've configured an error Interceptor like this:

RestangularProvider.setErrorInterceptor(
    function ( response ) {
        if ( response.status == 401 ) {
        dialogs.error("Unauthorized - Error 401", "You must be authenticated in order to access this content.")
            .result.then( function () {
                $location.path("/login");
            });
        }
        else {
            // Some other unknown Error.
            console.log( response );
            dialogs.error(response.statusText + " - Error " + response.status,
                "An unknown error has occurred.<br>Details: " + response.data);
        }
        // Stop the promise chain.
        return false;
    }
);

then, on another place, I make a POST call with an error handling.

function saveApple( apple ) {
    Restangular.all("apple/save").post( apple ).then(
        function ( response ) {
            console.log("Saved");
        },
        function ( response ) {
            // This is not being called.
            console.log("Error with status code", response.status);
        }
    );
}

I understand that, my "second" error handler is not being called because I'm returning false on the ErrorInterceptor.

But how can I work this around? I have lots of "REST operations" in my app, and only few of them, I want a customized behavior when something goes wrong.

So far, the only work-around I thought of, is to make the ErrorInterceptor return true, and for every other REST operations, I copy-paste the same error handler (a more general one). But this would be the last thing I would do.

Right now, is flowing like this:

  • ErrorInterceptor > End.

If possible, I want it to be like this: (Only for specific methods - not all).

  • ErrorInterceptor > Especific_ErrorHandler (if Exists) > End.

it can also be like this:

  • Especific_ErrorHandler (if Exists) > ErrorInterceptor > End.

Either way works for me.

References:

https://github.com/mgonto/restangular#seterrorinterceptor https://github.com/mgonto/restangular#how-can-i-handle-errors

Thanks in Advance!

Answer

dnozay picture dnozay · Jan 25, 2015

Here is your code:

RestangularProvider.setErrorInterceptor(
    function ( response ) {
        if ( response.status == 401 ) {
        dialogs.error("Unauthorized - Error 401", "You must be authenticated in order to access this content.")
            .result.then( function () {
                $location.path("/login");
            });
        }
        else {
            // Some other unknown Error.
            console.log( response );
            dialogs.error(response.statusText + " - Error " + response.status,
                "An unknown error has occurred.<br>Details: " + response.data);
        }
        // Stop the promise chain.
        return false;
    }
);

Why are you using an interceptor? - because you want dialogs across the board for displaying error messags.

Stopping promise chain, is it bad practice?

I don't know. Many people use error callbacks; and one use-case for error callbacks is to do some cleanup. If you kill the promise chain, how do you ensure the cleanup is done? Stopping the promise chain means your error callbacks, your catch blocks, and your finally blocks won't get called.

In the docs, the cleanup is done, you can see that deferred.reject is passed along. https://github.com/mgonto/restangular#seterrorinterceptor Maybe you misunderstood the example that was in the docs.

Possible solution #1

        // DON'T stop the promise chain.
        return true;

Possible solution #2

Don't handle unknown errors in the error interceptor.

RestangularProvider.setErrorInterceptor(
    function ( response ) {
        if ( response.status == 401 ) {
            dialogs.error("Unauthorized - Error 401", "You must be authenticated in order to access this content.")
                .result.then( function () {
                   $location.path("/login");
                });
            // Stop the promise chain.
            // all unauthorized access are handled the same.
            return false;
        }
        // Some other unknown Error.
        console.log( response );
        dialogs.error(response.statusText + " - Error " + response.status,
            "An unknown error has occurred.<br>Details: " + response.data);
        }
        // DON'T stop promise chain since error is not handled
        return true;
    }
);

Possible solution #3

call reject when you stop the promise chain.

RestangularProvider.setErrorInterceptor(
    function ( response, deferred, responseHandler ) {
        if ( response.status == 401 ) {
            dialogs.error("Unauthorized - Error 401", "You must be authenticated in order to access this content.")
                .result.then( function () {
                   // continue promise chain in this callback.
                   deferred.reject("unauthorized");
                   $location.path("/login");
                });
            // Stop the promise chain here
            // all unauthorized access are handled the same.
            return false;
        }
        // Some other unknown Error.
        console.log( response );
        dialogs.error(response.statusText + " - Error " + response.status,
            "An unknown error has occurred.<br>Details: " + response.data);
        }
        // DON'T stop promise chain since error is not handled
        return true;
    }
);