Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restangular - How to override Error Interceptors

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!

like image 945
sam Avatar asked Jan 18 '15 14:01

sam


2 Answers

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;
    }
);
like image 109
dnozay Avatar answered Oct 25 '22 05:10

dnozay


Yes, you can create custom httpErrorHandler.

  • First you need to create a .factory, let's call it httpErrorHandler

.factory('httpErrorHandler', function ($rootScope) {
  return {
    'error': function (rejection) {
      if (rejection.status === 422) {
        $rootScope.$broadcast('422_error', rejection.data);
      } else if (rejection.status === 403) {
        $rootScope.$broadcast('403_error', rejection.data);
      } else {
        $rootScope.$broadcast('unknown', rejection.data);
      }
      return $q.reject(rejection);
    }
  };
}
  • Then register that factory to the $httpProvider interceptors

.config(function ($httpProvider) {
  $httpProvider.interceptors.push('httpErrorHandler');
});

Then just catch that $rootScope events anywhere in the application and handle them, or add some logic inside the interceptor.

I hope this will work as expected.

like image 38
Tome Pejoski Avatar answered Oct 25 '22 05:10

Tome Pejoski