Maîtrisez $http et $resource AngularJS 1.x pour consommer des REST APIs : interceptors, promises, ngResource et patterns avancés.
$http : introduction et configuration
$http est le service built-in d'AngularJS pour effectuer des requêtes HTTP. Il encapsule XMLHttpRequest et retourne des promises (objets $q) que vous chaînez avec .then() et .catch().
Contrairement à fetch() natif ou axios, $http intègre automatiquement le cycle $digest d'AngularJS : toute réponse HTTP déclenche une mise à jour de l'UI sans appel manuel à $scope.$apply().
// Injection de $http dans un service ou controller
angular.module('monApp')
.service('ApiService', function($http) {
// $http est prêt à l'emploi, aucune configuration minimale requise
// Par défaut : Content-Type: application/json, XSRF protection activée
this.ping = function() {
return $http.get('/api/health');
// Retourne une promise : { data, status, headers, config, statusText }
};
});
Configuration globale de $http
// Configurer $http globalement dans la phase config()
angular.module('monApp')
.config(function($httpProvider) {
// Ajouter un header Authorization à toutes les requêtes
$httpProvider.defaults.headers.common['Authorization'] =
'Bearer ' + localStorage.getItem('token');
// Désactiver le cache par défaut (utile en développement)
$httpProvider.defaults.cache = false;
// Timeout global de 10 secondes pour toutes les requêtes
$httpProvider.defaults.timeout = 10000;
// Activer les credentials CORS (cookies cross-domain)
$httpProvider.defaults.withCredentials = true;
});
Méthodes GET, POST, PUT, DELETE
$http expose des méthodes de raccourci pour chaque verbe HTTP. Chaque méthode retourne une promise résolue avec un objet de réponse contenant data, status, headers et config.
GET — Lire des données
// Récupère la liste des articles avec paramètres de requête
angular.module('monApp')
.service('ArticleService', function($http) {
this.getAll = function(page, limit) {
return $http.get('/api/articles', {
// params est converti automatiquement en query string
// → /api/articles?page=1&limit=20
params: { page: page, limit: limit }
}).then(function(response) {
// response.data contient le corps de la réponse parsé
return response.data;
});
};
// Récupère un article par son slug
this.getBySlug = function(slug) {
return $http.get('/api/articles/' + slug)
.then(function(res) { return res.data; });
};
});
POST — Créer une ressource
// Crée un nouvel article avec les données envoyées en JSON
this.create = function(articleData) {
return $http.post('/api/articles', articleData)
// angularJS sérialise automatiquement l'objet en JSON
.then(function(response) {
// response.status === 201 (Created)
return response.data; // l'article créé avec son ID
})
.catch(function(error) {
// error.status = code HTTP (400, 401, 500...)
// error.data = corps de la réponse d'erreur
console.error('Erreur création:', error.status, error.data);
return Promise.reject(error);
});
};
PUT / PATCH — Mettre à jour
// PUT remplace la ressource complète
this.update = function(id, data) {
return $http.put('/api/articles/' + id, data)
.then(function(res) { return res.data; });
};
// PATCH met à jour partiellement (envoie seulement les champs modifiés)
this.patch = function(id, changes) {
return $http.patch('/api/articles/' + id, changes)
.then(function(res) { return res.data; });
};
DELETE — Supprimer
// Supprime un article par son ID
this.remove = function(id) {
return $http.delete('/api/articles/' + id)
.then(function(response) {
// response.status === 204 (No Content) si suppression réussie
return true;
});
};
L'objet de configuration $http
Au lieu des méthodes de raccourci, vous pouvez utiliser $http(config) directement pour un contrôle total sur la requête.
// Requête complète avec tous les paramètres disponibles
$http({
method: 'POST',
url: '/api/upload',
// Corps de la requête (object, string, FormData...)
data: formData,
// Headers spécifiques à cette requête (surcharge les defaults)
headers: {
'Content-Type': undefined, // undefined = AngularJS choisit (FormData auto)
'X-Custom-Header': 'valeur',
},
// Paramètres query string
params: { version: '2', debug: true },
// Timeout en ms (annule la requête si dépassé)
timeout: 30000,
// Réponse en ArrayBuffer, Blob, Document, JSON (défaut), text
responseType: 'blob',
// Téléchargement : notifie la progression
eventHandlers: {
progress: function(event) {
var percent = Math.round(event.loaded / event.total * 100);
console.log('Upload:', percent + '%');
}
},
}).then(function(response) {
console.log('Succès:', response.status, response.data);
}).catch(function(error) {
console.error('Échec:', error.status, error.statusText);
});
Interceptors $http
Les interceptors permettent d'intercepter toutes les requêtes et réponses HTTP de l'application. Ils sont idéaux pour l'authentification, le logging, la gestion d'erreurs globale et l'affichage d'un indicateur de chargement.
// Interceptor complet : auth + loading + retry
angular.module('monApp')
.factory('HttpInterceptor', function($q, $injector) {
var pendingRequests = 0;
return {
// Intercepte chaque requête sortante
request: function(config) {
pendingRequests++;
// Ajoute le token JWT à chaque requête vers notre API
var token = localStorage.getItem('auth_token');
if (token && config.url.indexOf('/api/') !== -1) {
config.headers['Authorization'] = 'Bearer ' + token;
}
// Active un spinner de chargement global
$injector.get('LoadingService').show();
return config; // toujours retourner config (ou une promise)
},
// Intercepte les réponses réussies
response: function(response) {
pendingRequests--;
if (pendingRequests === 0) {
$injector.get('LoadingService').hide();
}
return response;
},
// Intercepte les erreurs HTTP
responseError: function(rejection) {
pendingRequests--;
if (pendingRequests === 0) {
$injector.get('LoadingService').hide();
}
// Token expiré → redirige vers la page de connexion
if (rejection.status === 401) {
$injector.get('$state').go('login');
return $q.reject(rejection);
}
// Serveur indisponible → message d'erreur
if (rejection.status === 503) {
$injector.get('NotifService').error('Serveur temporairement indisponible');
}
return $q.reject(rejection); // toujours rejeter pour propager l'erreur
},
};
})
// Enregistrement de l'interceptor
.config(function($httpProvider) {
$httpProvider.interceptors.push('HttpInterceptor');
});
ngResource et $resource
ngResource est un module optionnel d'AngularJS qui fournit $resource, une abstraction de haut niveau pour les API RESTful. Il génère automatiquement les méthodes CRUD à partir d'un pattern d'URL.
// Installation (en plus d'angular.js)
// <script src="angular-resource.js"></script>
// Déclaration du module avec ngResource
angular.module('monApp', ['ngResource']);
// Définition d'une ressource REST
angular.module('monApp')
.factory('Article', function($resource) {
return $resource(
'/api/articles/:id', // pattern URL avec paramètre :id
{ id: '@id' }, // valeur par défaut de :id (depuis l'objet)
{
// Méthodes personnalisées (en plus des méthodes par défaut)
update: { method: 'PUT' }, // $resource n'a pas PUT par défaut
patch: { method: 'PATCH' },
search: {
method: 'GET',
url: '/api/articles/search', // URL différente pour la recherche
isArray: true, // la réponse est un tableau
},
}
);
// $resource génère automatiquement :
// Article.query() → GET /api/articles (tableau)
// Article.get({id:1}) → GET /api/articles/1 (objet)
// Article.save(data) → POST /api/articles (créer)
// Article.delete({id}) → DELETE /api/articles/:id (supprimer)
});
CRUD complet avec $resource
// Controller utilisant $resource pour un CRUD complet
angular.module('monApp')
.controller('ArticleCtrl', function($scope, Article) {
// READ — charge tous les articles
$scope.articles = Article.query(); // retourne un tableau vide, rempli async
// READ ONE — charge un article par ID
$scope.loadArticle = function(id) {
$scope.current = Article.get({ id: id });
};
// CREATE — crée un nouvel article
$scope.create = function(formData) {
var article = new Article(formData);
article.$save(function(saved) {
// Succès : $save appelle POST /api/articles
$scope.articles.push(saved);
$scope.formData = {}; // reset du formulaire
}, function(error) {
// Erreur : afficher un message
$scope.error = 'Erreur lors de la création : ' + error.data.message;
});
};
// UPDATE — met à jour un article existant
$scope.update = function(article) {
article.$update(function() {
// $update appelle PUT /api/articles/:id
console.log('Article mis à jour');
});
};
// DELETE — supprime un article
$scope.remove = function(article) {
article.$delete(function() {
// $delete appelle DELETE /api/articles/:id
var idx = $scope.articles.indexOf(article);
$scope.articles.splice(idx, 1);
});
};
// CUSTOM ACTION — recherche d'articles
$scope.search = function(query) {
$scope.results = Article.search({ q: query });
};
});
Gestion des erreurs
// Service de gestion d'erreurs centralisé
angular.module('monApp')
.service('ErrorHandler', function($q, NotifService) {
// Traite une erreur HTTP et retourne un message lisible
this.handle = function(error) {
var message;
switch (error.status) {
case 400:
// Erreur de validation : afficher les détails
message = error.data.message || 'Données invalides';
if (error.data.errors) {
message += ' : ' + Object.values(error.data.errors).join(', ');
}
break;
case 401:
message = 'Session expirée. Veuillez vous reconnecter.';
break;
case 403:
message = 'Vous n\'avez pas les droits pour cette action.';
break;
case 404:
message = 'La ressource demandée est introuvable.';
break;
case 422:
message = 'Données incorrectes : ' + (error.data.message || '');
break;
case 429:
message = 'Trop de requêtes. Veuillez patienter.';
break;
case 500:
message = 'Erreur serveur. Notre équipe a été notifiée.';
break;
default:
message = error.status === -1
? 'Pas de connexion internet.'
: 'Erreur inattendue (' + error.status + ')';
}
NotifService.error(message);
return $q.reject(error); // propage l'erreur après traitement
};
});
Migration vers HttpClient Angular
HttpClient remplace $http en Angular. La différence principale est que HttpClient retourne des Observables (RxJS) au lieu de Promises, ce qui ouvre la voie à des opérateurs puissants comme retry, debounceTime, switchMap.
| AngularJS $http | Angular HttpClient |
|---|---|
| $http.get(url) | this.http.get<T>(url) |
| $http.post(url, data) | this.http.post<T>(url, data) |
| .then(fn) | .subscribe(fn) ou pipe(map(fn)) |
| .catch(fn) | pipe(catchError(fn)) |
| Interceptors via $httpProvider | HttpInterceptorFn (fonctionnel) |
| $resource (ngResource) | httpResource() (Angular 21) |
| Promises ($q) | Observables (RxJS) |
// Équivalent HttpClient Angular 21 avec interceptor fonctionnel
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { catchError, throwError } from 'rxjs';
import { AuthService } from './auth.service';
import { Router } from '@angular/router';
// Interceptor fonctionnel (Angular 15+) — remplace la classe
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const auth = inject(AuthService);
const router = inject(Router);
// Clone la requête pour ajouter le header Authorization
const authReq = auth.token()
? req.clone({ setHeaders: { Authorization: 'Bearer ' + auth.token() } })
: req;
return next(authReq).pipe(
catchError(error => {
if (error.status === 401) {
router.navigate(['/login']);
}
return throwError(() => error);
})
);
};
httpResource() remplace avantageusement $resource — elle retourne des signals réactifs qui s'actualisent automatiquement quand les paramètres changent, sans subscribe explicite.