1

First project in AngularJS and I started creating my services (factories) that I made modular like this

angular.module('app.services.public', [])
    .factory('publicService', ['$http', function publicService($http) {
        var results = {};
        results.contact = function (name, email, message){
             return $http.get();
        };
        return results;
    }]);

That I then call in my main angular app by including it. When I call it, I need to listen for success or error

publicService.contact().success(callback).error(callback)

My question is, I'm going to be doing a lot of API requests through these services and seems to be bad code to listen to the error everytime since 90% of the time it will do the same thing.

How can I create a wrapper around the $http.get or around all factory calls?

So something like

apiCall = function (url, data, successCallback, errorCallback){
    $http.get(url,data).success(function(){
        successCallback()
    }).error(function(){
        if(errorCallback()){ errorCallback(); return; }
         // or display general error message
    })
}
0

3 Answers 3

1

I would recommend against converting promise-based into callback-based APIs. Angular adopted promises and it best to stay with them. Also, stay away from $http-specific .success/.error and use promise .then/.catch APIs.

How wide do you need to cast your net to handle $http errors?

1) Say, it only applies to your publicService service, then you can "handle" it at the each function:

.factory("publicService", function($http, $q){ 
    function handleError(){
      // invokes error handlers
    }
    return {

      onError: function(cb){
        // register error handlers
      },
      doSomethingA: function(){
        return $http.get("some/url/A")
                    .then(function(response){
                       return response.data;
                    })
                    .catch(function(error){
                       handleError(error);
                       return $q.reject(error); // still "rethrow" the error
                    }
      },
      doSomethingB: function(){
        // similar to above
      },
      // etc...
    };

})

Then you could separate request from error handling:

.controller("MainCtrl", function($scope, publicService){
   publicService.onError(function(error){
     $scope.showError = true; // or something like that
   })
})
.controller("FunctionACtrl", function($scope, publicService){
   publicService.doSomethingA()
                .then(function(data){
                  $scope.data = data;
                });
})

2) Of course, the above, would only apply to request made via publicService. If you want to catch all $http errors, you could implement an $http interceptors. I won't go into detail - there is enough info in documentation and elsewhere - but it would could work like below:

.factory("ErrorService", function(){
  return {
    onError: function(cb){
      // register error handlers
    },
    broadcastError: function(error){
      // invoke error handlers
    }
  };
})

Then in interceptor, use ErrorService as a dependency:

'responseError': function(rejection) {

   ErrorService.broadcastError(rejection);

   return $q.reject(rejection);
}

Then you could handle the errors globally:

.controller("MainCtrl", function($scope, ErrorService){
   ErrorService.onError(function(error){
     $scope.showError = true; // or something like that
   })
})
Sign up to request clarification or add additional context in comments.

3 Comments

Would be really helpful if you could develop a bit more on the second method.
@denislexic, there is some boilerplate code around creating interceptors - see here and here for more context
For reference to other people, this article is pretty good on explaining how it all works: webdeveasy.com/interceptors-in-angularjs-and-useful-examples
1

You have the right idea. You can do it easily with a Factory.

myApp.factory(APIService, function(publicService, $http) {
  return {

    // create methods in here
    ...

    contact: function(cb) {
      $http.get(url,data).success(cb).error(function(err){
        console.error('oh no!', err);
      });
    }
  };
});

Then you can use it in your controllers.

APIService.contact(function(data){
  console.log('response from the api!', data);
});

You can even move your error handler to its own factory as well.

Comments

1

I would suggest an implementation using angular's $q service.

angular.module('app.services.public', [])
    .factory('publicService', ['$http', '$q', function publicService($http, $q) {
        var results = {};
        results.contact = function (name, email, message){
             return $q.when($http.get());
        };
        return results;
    }]);

Or rather than use the $q.when(...) method you can use $q.deferred like so:

angular.module('app.services.public', [])
        .factory('publicService', ['$http', '$q', function publicService($http, $q) {
            var deferred = $q.deferred();
            var results = {};
            results.contact = function (name, email, message){
                 $http.get().success(function(data){
                      deferred.resolve({
                         // assumes data retried from http request has a title and price attribute
                         title: data.title,
                         cost: data.price});
                 }).error(function(data){
                       deferred.reject(data);
                 });
            };
            return deferred.promise;
        }]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.