Fatigué d’être limité à lire des données avec des requêtes AJAX GET? Voici le temps d’apprendre à utiliser le service $resource offert par Angular. Ce service a spécialement été conçu afin de simplifier les communications avec un serveur RESTful. Il permet d’effectuer les opérations de CRUD (Create Read Update Delete) efficacement.
Le service $resource est basé sur $http et possède la logique afin de sélectionner la bonne méthode HTTP en fonction de vos besoins. Donc, pour une opération de création, la méthode POST sera utilisée, pour une opération de lecture, la méthode GET sera utilisée et pour une opération de suppression, la méthode DELETE sera utilisée.
Installer ngResource
L’installation se fait en trois étapes : télécharger la dépendance, la configurer dans votre application Angular et vérifier que le .js est bien inclus dans votre app.
Avant de procéder à l’installation, vérifier que le module n’est pas déjà installé.
Téléchargement de ngResource
1 |
$ bower install angular-resource --save |
Configuration de ngResource
1 2 3 4 5 |
angular.module('fs3App', [ 'ngResource', ... 'ui.bootstrap' ]) |
angular-resource.js
La dernière étape consiste à vérifier que le fichier .js est bien inclus dans votre page. Cette librairie devrait être incluse après l’inclusion de angular.js
1 2 |
<script src="angular.js"> <script src="angular-resource.js"> |
Structure de l’API souhaitée
Afin de faciliter l’utilisation de $resource, votre API REST devrait être construit selon les spécifications du tableau suivant :
URL | VERBE HTTP | Corps du message (BODY) | Résultat |
http://api.com/post | GET | vide | Retourne tous les enregistrements |
http://api.com/post | POST | Chaîne JSON | Crée un nouveau Post |
http://api.com/post/:id | GET | vide | Retourne un seul Post |
http://api.com/post/:id | PUT | Chaîne JSON | Met à jour un Post |
http://api.com/post/:id | DELETE | vide | Supprime un Post |
Exemple d’utilisation de $resource
L’exemple suivant encapsule une ressource à l’intérieur d’un service nommé Post. Ce nouveau service pourra être injecté et utilisé dans vos contrôleurs.
1 2 3 4 5 6 |
var myApp = angular.module('fs3App'); myApp.service('Post', function($resource) { var restAPIUrl = 'http://localhost:3000'; return $resource(restAPIUrl + '/posts/:id', { id: '@id' } ); }); |
Pour les utilisateurs du générateur angular-fullstack, vous pouvez créer un squelette de service facilement.
Voici un exemple :
1 2 3 4 |
$ yo angular-fullstack:service nomDeMonService ? Where would you like to create this service? client/app/ create client/app/post/post.service.js create client/app/post/post.service.spec.js |
Utiliser votre service $resource dans un contrôleur
Le code suivant présente l’utilisation de notre nouveau service. Il démontre l’utilisation des fonctions query, get, delete et save.
Notez l’injection du service Post dans la fonction du contrôleur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
myApp.controller('ResourcedemoCtrl', function ($scope, Post) { // GET : Récupère tous les Posts $scope.posts = Post.query(); // GET : Récupère le Post #3 $scope.postToEdit = Post.get({id:3}); // DELETE : Supprime le Post #3 Post.delete({id:3}); // SAVE : Crée un nouveau Post var myPostObj = {title: 'Title', body: 'Body', userId:1}; Post.save(myPostObj); // SAVE : Crée un nouveau Post, version #2 var aPost = new Post(myPostObj); aPost.$save(); }); |
Le code précédent présente plusieurs méthodes d’un objet $resource, en voici un résumé :
- Post.get();
- Post.save();
- Post.query();
- Post.delete();
Lorsque la méthode get est lancée, un objet de type Resource est retourné, cet objet nous offre les méthodes suivantes :
- post.$save();
- post.$delete();
Une promesse avec $promise
Dans le mode asynchrone des appels AJAX, il est primordial de comprendre que l’objet retourné par Post.get(), est une promesse d’un objet dans le futur.
Lors de l’exécution de la commande suivante :
1 |
console.log(Post.get({id:3})); |
La console du navigateur nous affiche cela :
1 |
Resource {$promise: Promise, $resolved: false} |
En résumé, cet objet de type Resource, contient une promesse qui n’a pas été résolue. Donc, les données ne sont pas encore disponibles!
Quelques millisecondes plus tard, les données sont disponibles et $resolved est à true.
1 2 3 4 5 6 7 |
Resource {$promise: Promise, $resolved: true} $promise: Promise $resolved: true id: 3 title: "quasi exercitationem repellat qui ipsa sit aut" body: "molestiae porro eius odio et labore et velit aut" __proto__: Resource |
Ne soyez pas impatient
Pour la raison précédente, l’exemple suivant est erroné, puisque la promesse ne sera peut-être résolue au moment d’appeler la méthode $delete. Donc au moment d’appeler $delete, l’attribut myPost.id est indéfini.
1 2 |
var myPost = Post.get({id:3}); myPost.$delete(); |
Avec le $scope, c’est plus simple
Par contre, dans l’exemple suivant, en associant une ressource avec le $scope, tout se passe bien. Le mécanisme relié au $scope est programmé afin d’attendre que la promesse soit résolue avant d’afficher les données dans votre vue.
1 |
$scope.postToEdit = Post.get({id:3}); |
Autre exemple qui fonctionne aussi bien :
1 |
$scope.posts = Post.query(); |
Mise à jour d’un objet $resource avec PUT
Si vous désirez utiliser le verbe PUT, malheureusement, $resource ne supporte pas ce verbe. Il faut donc mettre à jour votre service en spécifiant le nom d’une nouvelle méthode et d’un nouveau verbe.
La signature de $resource possède l’attribut actions. Il est donc possible d’ajouter ou de modifier des actions par défaut.
1 |
$resource(url, [paramDefaults], [actions], options); |
Voyons comment faire en code :
1 2 3 4 5 6 7 |
myApp.service('Post', function($resource) { var APIUrl = 'http://localhost:3000'; return $resource(APIUrl + '/posts/:id', { id: '@id' }, { update: {method: 'PUT'} } ); }); |
Suite à cet ajout, vous pouvez utiliser la méthode update sur un objet de type $resource :
1 2 3 4 5 |
var post = Post.get({id:2}, function() { post.archived = true; post.$update(); }); |
Tests unitaires pour votre $resource
Puisque $resource est basé sur le service $http, on peut donc utiliser $httpBackend afin de tester le bon fonctionnement du code.
Vous avez préalablement utilisé when afin de simuler une réponse lors d’un appel de type GET.
1 |
$httpBackend.whenGET(url, [headers], [keys]); |
Il sera maintenant possible d’utiliser les méthodes when suivantes :
- whenDELETE(url, [headers], [keys]);
- whenPOST(url, [data], [headers], [keys]);
- whenPUT(url, [data], [headers], [keys]);
Ainsi que les méthodes expect correspondantes :
- expectDELETE(url, [headers], [keys]);
- expectPOST(url, [data], [headers], [keys]);
- expectPUT(url, [data], [headers], [keys]);
https://docs.angularjs.org/api/ngMock/service/$httpBackend
Besoin d’un API REST pour tester $resource?
Maintenant, voyons comment mettre en place un API REST de développement.
L’article suivant présente 2 solutions : Jsonplaceholder et json-server.
- jsonplaceholder est un service en ligne aussi disponible en installation locale. Par contre, il demeure en lecture seule et simule des réponses lorsque vos lancez les opérations de modification.
- json-server doit être installé localement, mais permet les opérations de mise à jour.
Pour en avoir plus, lisez l’article : Mettre en place un API REST de développement.
Conclusion
Faire du CRUD avec $resource c’est plus simple ;)
Références
- AngularJS: API: $resource
- https://docs.angularjs.org/api/ngResource/service/$resource
- AngularJS: API: ngResource
- https://docs.angularjs.org/api/ngResource
- PublicAPIs | Directory of public APIs for web and mobile
- https://www.publicapis.com/
- httpbin(1): HTTP Client Testing Service
- http://httpbin.org/
- typicode/jsonplaceholder: A simple fake REST API server
- https://github.com/typicode/jsonplaceholder
- typicode/json-server: Get a full fake REST API with zero coding in less than 30 seconds (seriously)
- https://github.com/typicode/json-server
- REST Services – Free Developer Tutorials
- http://www.freedevelopertutorials.com/angularjs-tutorial/rest-services/
- AngularJS: API: $q
- https://docs.angularjs.org/api/ng/service/$q
Laisser un commentaire
Participez-vous à la discussion?N'hésitez pas à contribuer!