Blog
Gestion d'erreur abstraite avec AngularJS

Partager

Il est très simple d’effectuer une requête AJAX en utilisant le service $http avec AngularJS :

$http.post(
	"http://www.bigint.fr/test", 
	{"foo":"bar"}
)
.success(function(data) {
    $scope.data = data;
}).error(function(data) {
    //draw a modal/alert containing the error message
});

Cependant, c’est contraignant de devoir appeler et gérer manuellement le callback d’error à chaque requête AJAX.

Il existe un moyen d’améliorer la maintenabilité de votre code et d’appliquer la philosophie DRY (Don't Repeat Yourself).

HTTP Interceptor

Depuis la version 1.2, AngularJS met à notre disposition un moyen d'intercepter les requêtes HTTP : les interceptors.

Ce service permet d’intercepter les requêtes avant qu’elles ne soient envoyées au serveur et d’intercepter les réponses avant qu’elles ne soient transmises au client.

Il faut donc créer le service suivant :

// register the interceptor as a service
factory('HttpInterceptor', ['$q', '$rootScope', function($q, $rootScope) {
       return {
            // On request success
            request : function(config) {
                // Return the config or wrap it in a promise if blank.
                return config || $q.when(config);
            },

            // On request failure
            requestError : function(rejection) {
                //console.log(rejection); // Contains the data about the error on the request.  
                // Return the promise rejection.
                return $q.reject(rejection);
            },

            // On response success
            response : function(response) {
                //console.log(response); // Contains the data from the response.
                // Return the response or promise.
                return response || $q.when(response);
            },

            // On response failure
            responseError : function(rejection) {
                //console.log(rejection); // Contains the data about the error.
                //Check whether the intercept param is set in the config array. 
                //If the intercept param is missing or set to true, we display a modal containing the error
                if (typeof rejection.config.intercept === 'undefined' || rejection.config.intercept)
                {
                    //emitting an event to draw a modal using angular bootstrap
                    $rootScope.$emit('errorModal', rejection.data);
                }

                // Return the promise rejection.
                return $q.reject(rejection);
            }
        };
 }]);

Cette solution est satisfaisante mais un poil trop générique. Comment faire pour ne pas intercepter toutes les requêtes ? Par exemple pour effectuer un traitement spécifique pour une requête particulière.

Il faut savoir qu’avec $http (ou $resource), il est possible de passer un objet de configuration. AngularJS définit certaines propriétés mais il est possible d’ajouter les vôtres. Il est possible de récupérer ce tableau de configuration dans notre interceptor. Dans ce cas, on va utiliser une propriété propre à notre application : 'intercept'.

On doit modifier notre code pour afficher la modal que lorsque 'intercept' est défini à true :

 if (typeof rejection.config.intercept === 'undefined' || rejection.config.intercept)
 {
  //emitting an event to draw a modal using angular bootstrap
  $rootScope.$emit('errorModal', rejection.data);
 }

Notre requête http particulière doit utiliser le paramètre 'intercept' :

$http.post(
	"http://www.bigint.fr/test", 
	{"foo":"bar"},
	{intercept: false}
)

Enfin il ne faut pas oublier d’enregistrer ce service sur le module racine de votre application :

app.config(['$httpProvider', function($httpProvider) {
		// Add the interceptor to the $httpProvider to intercept http calls
		$httpProvider.interceptors.push('HttpInterceptor');
	}]);

Autres utilisations de l'interceptor

Les applications offertes par un tel service sont variées. A BigInt, nous l'utilisons pour :

  • Afficher une notice lorsqu'une requête avec un long traitement part et l’effacer lorsqu'on reçoit la réponse (pour un import/export par exemple).
  • S’assurer que deux requêtes identiques émanant d'un même client ne soient pas transmises au serveur pour ne pas le surcharger inutilement.
comments powered by Disqus